├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── arm64ec_dllimport ├── README.md ├── dllimport.c ├── example.cpp ├── example.sln ├── example.vcxproj └── example.vcxproj.filters ├── arm64x_reloc_tools ├── .pre-commit-config.yaml ├── README.md ├── chpe_fixup.json ├── data │ ├── shellcodearm64.bin │ └── shellcodex64.bin ├── main.py ├── pe_patcher.py ├── poetry.lock └── pyproject.toml ├── assets └── chameleon.PNG ├── chpe_scanner ├── .gitignore ├── README.md ├── data │ ├── chpe_list.csv │ └── non_chpe_list.csv ├── main.py ├── poetry.lock └── pyproject.toml ├── docs ├── 404.html ├── arm64x_reloc_obfuscation │ └── index.html ├── assets │ ├── DATA_DIRECTORY_EXPORT.PNG │ ├── DVRT_annotated.png │ ├── arm64x_disas_0x7000_dynamic.png │ ├── arm64x_disas_0x7000_static.png │ ├── arm64x_reloc_decoding.png │ ├── arm64x_reloc_obfus.gif │ ├── code1.PNG │ ├── code2.PNG │ ├── code3.PNG │ ├── code4.PNG │ ├── code5.PNG │ ├── code6.PNG │ ├── dvrt_user32_structure.PNG │ ├── export_address_table_x64.PNG │ ├── export_func_addr_arm64.PNG │ ├── export_func_addr_x64.PNG │ ├── export_is_different.png │ ├── for_figure_creation.pptx │ ├── image_section_header.PNG │ ├── image_sections_after.PNG │ ├── image_sections_before.PNG │ ├── images │ │ └── favicon.png │ ├── javascripts │ │ ├── bundle.b1047164.min.js │ │ ├── bundle.b1047164.min.js.map │ │ ├── lunr │ │ │ ├── min │ │ │ │ ├── lunr.ar.min.js │ │ │ │ ├── lunr.da.min.js │ │ │ │ ├── lunr.de.min.js │ │ │ │ ├── lunr.du.min.js │ │ │ │ ├── lunr.es.min.js │ │ │ │ ├── lunr.fi.min.js │ │ │ │ ├── lunr.fr.min.js │ │ │ │ ├── lunr.hi.min.js │ │ │ │ ├── lunr.hu.min.js │ │ │ │ ├── lunr.it.min.js │ │ │ │ ├── lunr.ja.min.js │ │ │ │ ├── lunr.jp.min.js │ │ │ │ ├── lunr.multi.min.js │ │ │ │ ├── lunr.nl.min.js │ │ │ │ ├── lunr.no.min.js │ │ │ │ ├── lunr.pt.min.js │ │ │ │ ├── lunr.ro.min.js │ │ │ │ ├── lunr.ru.min.js │ │ │ │ ├── lunr.stemmer.support.min.js │ │ │ │ ├── lunr.sv.min.js │ │ │ │ ├── lunr.th.min.js │ │ │ │ ├── lunr.tr.min.js │ │ │ │ ├── lunr.vi.min.js │ │ │ │ └── lunr.zh.min.js │ │ │ ├── tinyseg.js │ │ │ └── wordcut.js │ │ └── workers │ │ │ ├── search.fcfe8b6d.min.js │ │ │ └── search.fcfe8b6d.min.js.map │ ├── ksarm64_h_CHPEV2.PNG │ ├── messageboxa_body_arm64.PNG │ ├── messageboxa_body_junk_x86.PNG │ ├── messageboxa_export_x86.PNG │ ├── messageboxa_exportx86_to_body.png │ ├── messageboxa_impl.PNG │ ├── ntheader_machine.PNG │ ├── schematic_picture_of_arm64x.png │ ├── sharp_function_is_called.png │ ├── sharp_messageboxa_exp.PNG │ ├── sharp_messageboxa_impl.PNG │ └── stylesheets │ │ ├── main.a57b2b03.min.css │ │ ├── main.a57b2b03.min.css.map │ │ ├── palette.3f5d1f46.min.css │ │ └── palette.3f5d1f46.min.css.map ├── index.html ├── new_reloc_chpev2 │ └── index.html ├── search │ └── search_index.json ├── sitemap.xml └── sitemap.xml.gz ├── docs_src ├── mkdocs.yml ├── poetry.lock ├── pyproject.toml └── src │ ├── arm64x_reloc_obfuscation.md │ ├── assets │ ├── DATA_DIRECTORY_EXPORT.PNG │ ├── DVRT_annotated.png │ ├── arm64x_disas_0x7000_dynamic.png │ ├── arm64x_disas_0x7000_static.png │ ├── arm64x_reloc_decoding.png │ ├── arm64x_reloc_obfus.gif │ ├── code1.PNG │ ├── code2.PNG │ ├── code3.PNG │ ├── code4.PNG │ ├── code5.PNG │ ├── code6.PNG │ ├── dvrt_user32_structure.PNG │ ├── export_address_table_x64.PNG │ ├── export_func_addr_arm64.PNG │ ├── export_func_addr_x64.PNG │ ├── export_is_different.png │ ├── for_figure_creation.pptx │ ├── image_section_header.PNG │ ├── image_sections_after.PNG │ ├── image_sections_before.PNG │ ├── ksarm64_h_CHPEV2.PNG │ ├── messageboxa_body_arm64.PNG │ ├── messageboxa_body_junk_x86.PNG │ ├── messageboxa_export_x86.PNG │ ├── messageboxa_exportx86_to_body.png │ ├── messageboxa_impl.PNG │ ├── ntheader_machine.PNG │ ├── schematic_picture_of_arm64x.png │ ├── sharp_function_is_called.png │ ├── sharp_messageboxa_exp.PNG │ └── sharp_messageboxa_impl.PNG │ ├── index.md │ └── new_reloc_chpev2.md ├── ghidra_scripts ├── README.md ├── assets │ ├── after_reloc.PNG │ ├── before_reloc.PNG │ ├── fixup_records.PNG │ └── popup_after_reloc.PNG ├── build.gradle ├── gradlew ├── gradlew.bat └── src │ └── main │ └── java │ ├── ApplyChpeFixup.java │ ├── ShowChpeFixup.java │ └── chpe │ └── ChpeFixup.java └── hybrid_aux_iat ├── HybridAuxIAT.sln ├── HybridAuxIATHooking ├── .clang-format ├── HybridAuxIATHooking.vcxproj ├── HybridAuxIATHooking.vcxproj.filters └── Main.cpp ├── README.md ├── arm64ecext ├── .clang-format ├── arm64ecext.def ├── arm64ecext.vcxproj ├── arm64ecext.vcxproj.filters ├── chpe_utils.cpp ├── chpe_utils.h ├── dbg_ctl_wrapper.hpp ├── dbg_ext_main.cpp ├── dllmain.cpp ├── framework.h ├── pch.cpp ├── pch.h ├── pe_utils.cpp ├── pe_utils.h ├── utils.cpp └── utils.h └── assets └── HybridAuxIATHooking.gif /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | gradle 4 | *_jp.md 5 | *.zip 6 | *.exe* 7 | *_mod 8 | __pycache__ 9 | !arm64x_tools/data/*.exe 10 | ## Ignore Visual Studio temporary files, build results, and 11 | ## files generated by popular Visual Studio add-ons. 12 | ## 13 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 14 | 15 | # User-specific files 16 | *.rsuser 17 | *.suo 18 | *.user 19 | *.userosscache 20 | *.sln.docstates 21 | 22 | # User-specific files (MonoDevelop/Xamarin Studio) 23 | *.userprefs 24 | 25 | # Mono auto generated files 26 | mono_crash.* 27 | 28 | # Build results 29 | [Dd]ebug/ 30 | [Dd]ebugPublic/ 31 | [Rr]elease/ 32 | [Rr]eleases/ 33 | x64/ 34 | x86/ 35 | [Ww][Ii][Nn]32/ 36 | [Aa][Rr][Mm]/ 37 | [Aa][Rr][Mm]64/ 38 | bld/ 39 | [Bb]in/ 40 | [Oo]bj/ 41 | [Oo]ut/ 42 | [Ll]og/ 43 | [Ll]ogs/ 44 | 45 | # Visual Studio 2015/2017 cache/options directory 46 | .vs/ 47 | # Uncomment if you have tasks that create the project's static files in wwwroot 48 | #wwwroot/ 49 | 50 | # Visual Studio 2017 auto generated files 51 | Generated\ Files/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | # NUnit 58 | *.VisualState.xml 59 | TestResult.xml 60 | nunit-*.xml 61 | 62 | # Build Results of an ATL Project 63 | [Dd]ebugPS/ 64 | [Rr]eleasePS/ 65 | dlldata.c 66 | 67 | # Benchmark Results 68 | BenchmarkDotNet.Artifacts/ 69 | 70 | # .NET Core 71 | project.lock.json 72 | project.fragment.lock.json 73 | artifacts/ 74 | 75 | # ASP.NET Scaffolding 76 | ScaffoldingReadMe.txt 77 | 78 | # StyleCop 79 | StyleCopReport.xml 80 | 81 | # Files built by Visual Studio 82 | *_i.c 83 | *_p.c 84 | *_h.h 85 | *.ilk 86 | *.meta 87 | *.obj 88 | *.iobj 89 | *.pch 90 | *.pdb 91 | *.ipdb 92 | *.pgc 93 | *.pgd 94 | *.rsp 95 | *.sbr 96 | *.tlb 97 | *.tli 98 | *.tlh 99 | *.tmp 100 | *.tmp_proj 101 | *_wpftmp.csproj 102 | *.log 103 | *.vspscc 104 | *.vssscc 105 | .builds 106 | *.pidb 107 | *.svclog 108 | *.scc 109 | 110 | # Chutzpah Test files 111 | _Chutzpah* 112 | 113 | # Visual C++ cache files 114 | ipch/ 115 | *.aps 116 | *.ncb 117 | *.opendb 118 | *.opensdf 119 | *.sdf 120 | *.cachefile 121 | *.VC.db 122 | *.VC.VC.opendb 123 | 124 | # Visual Studio profiler 125 | *.psess 126 | *.vsp 127 | *.vspx 128 | *.sap 129 | 130 | # Visual Studio Trace Files 131 | *.e2e 132 | 133 | # TFS 2012 Local Workspace 134 | $tf/ 135 | 136 | # Guidance Automation Toolkit 137 | *.gpState 138 | 139 | # ReSharper is a .NET coding add-in 140 | _ReSharper*/ 141 | *.[Rr]e[Ss]harper 142 | *.DotSettings.user 143 | 144 | # TeamCity is a build add-in 145 | _TeamCity* 146 | 147 | # DotCover is a Code Coverage Tool 148 | *.dotCover 149 | 150 | # AxoCover is a Code Coverage Tool 151 | .axoCover/* 152 | !.axoCover/settings.json 153 | 154 | # Coverlet is a free, cross platform Code Coverage Tool 155 | coverage*.json 156 | coverage*.xml 157 | coverage*.info 158 | 159 | # Visual Studio code coverage results 160 | *.coverage 161 | *.coveragexml 162 | 163 | # NCrunch 164 | _NCrunch_* 165 | .*crunch*.local.xml 166 | nCrunchTemp_* 167 | 168 | # MightyMoose 169 | *.mm.* 170 | AutoTest.Net/ 171 | 172 | # Web workbench (sass) 173 | .sass-cache/ 174 | 175 | # Installshield output folder 176 | [Ee]xpress/ 177 | 178 | # DocProject is a documentation generator add-in 179 | DocProject/buildhelp/ 180 | DocProject/Help/*.HxT 181 | DocProject/Help/*.HxC 182 | DocProject/Help/*.hhc 183 | DocProject/Help/*.hhk 184 | DocProject/Help/*.hhp 185 | DocProject/Help/Html2 186 | DocProject/Help/html 187 | 188 | # Click-Once directory 189 | publish/ 190 | 191 | # Publish Web Output 192 | *.[Pp]ublish.xml 193 | *.azurePubxml 194 | # Note: Comment the next line if you want to checkin your web deploy settings, 195 | # but database connection strings (with potential passwords) will be unencrypted 196 | *.pubxml 197 | *.publishproj 198 | 199 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 200 | # checkin your Azure Web App publish settings, but sensitive information contained 201 | # in these scripts will be unencrypted 202 | PublishScripts/ 203 | 204 | # NuGet Packages 205 | *.nupkg 206 | # NuGet Symbol Packages 207 | *.snupkg 208 | # The packages folder can be ignored because of Package Restore 209 | **/[Pp]ackages/* 210 | # except build/, which is used as an MSBuild target. 211 | !**/[Pp]ackages/build/ 212 | # Uncomment if necessary however generally it will be regenerated when needed 213 | #!**/[Pp]ackages/repositories.config 214 | # NuGet v3's project.json files produces more ignorable files 215 | *.nuget.props 216 | *.nuget.targets 217 | 218 | # Microsoft Azure Build Output 219 | csx/ 220 | *.build.csdef 221 | 222 | # Microsoft Azure Emulator 223 | ecf/ 224 | rcf/ 225 | 226 | # Windows Store app package directories and files 227 | AppPackages/ 228 | BundleArtifacts/ 229 | Package.StoreAssociation.xml 230 | _pkginfo.txt 231 | *.appx 232 | *.appxbundle 233 | *.appxupload 234 | 235 | # Visual Studio cache files 236 | # files ending in .cache can be ignored 237 | *.[Cc]ache 238 | # but keep track of directories ending in .cache 239 | !?*.[Cc]ache/ 240 | 241 | # Others 242 | ClientBin/ 243 | ~$* 244 | *~ 245 | *.dbmdl 246 | *.dbproj.schemaview 247 | *.jfm 248 | *.pfx 249 | *.publishsettings 250 | orleans.codegen.cs 251 | 252 | # Including strong name files can present a security risk 253 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 254 | #*.snk 255 | 256 | # Since there are multiple workflows, uncomment next line to ignore bower_components 257 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 258 | #bower_components/ 259 | 260 | # RIA/Silverlight projects 261 | Generated_Code/ 262 | 263 | # Backup & report files from converting an old project file 264 | # to a newer Visual Studio version. Backup files are not needed, 265 | # because we have git ;-) 266 | _UpgradeReport_Files/ 267 | Backup*/ 268 | UpgradeLog*.XML 269 | UpgradeLog*.htm 270 | ServiceFabricBackup/ 271 | *.rptproj.bak 272 | 273 | # SQL Server files 274 | *.mdf 275 | *.ldf 276 | *.ndf 277 | 278 | # Business Intelligence projects 279 | *.rdl.data 280 | *.bim.layout 281 | *.bim_*.settings 282 | *.rptproj.rsuser 283 | *- [Bb]ackup.rdl 284 | *- [Bb]ackup ([0-9]).rdl 285 | *- [Bb]ackup ([0-9][0-9]).rdl 286 | 287 | # Microsoft Fakes 288 | FakesAssemblies/ 289 | 290 | # GhostDoc plugin setting file 291 | *.GhostDoc.xml 292 | 293 | # Node.js Tools for Visual Studio 294 | .ntvs_analysis.dat 295 | node_modules/ 296 | 297 | # Visual Studio 6 build log 298 | *.plg 299 | 300 | # Visual Studio 6 workspace options file 301 | *.opt 302 | 303 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 304 | *.vbw 305 | 306 | # Visual Studio LightSwitch build output 307 | **/*.HTMLClient/GeneratedArtifacts 308 | **/*.DesktopClient/GeneratedArtifacts 309 | **/*.DesktopClient/ModelManifest.xml 310 | **/*.Server/GeneratedArtifacts 311 | **/*.Server/ModelManifest.xml 312 | _Pvt_Extensions 313 | 314 | # Paket dependency manager 315 | .paket/paket.exe 316 | paket-files/ 317 | 318 | # FAKE - F# Make 319 | .fake/ 320 | 321 | # CodeRush personal settings 322 | .cr/personal 323 | 324 | # Python Tools for Visual Studio (PTVS) 325 | __pycache__/ 326 | *.pyc 327 | 328 | # Cake - Uncomment if you are using it 329 | # tools/** 330 | # !tools/packages.config 331 | 332 | # Tabs Studio 333 | *.tss 334 | 335 | # Telerik's JustMock configuration file 336 | *.jmconfig 337 | 338 | # BizTalk build output 339 | *.btp.cs 340 | *.btm.cs 341 | *.odx.cs 342 | *.xsd.cs 343 | 344 | # OpenCover UI analysis results 345 | OpenCover/ 346 | 347 | # Azure Stream Analytics local run output 348 | ASALocalRun/ 349 | 350 | # MSBuild Binary and Structured Log 351 | *.binlog 352 | 353 | # NVidia Nsight GPU debugger configuration file 354 | *.nvuser 355 | 356 | # MFractors (Xamarin productivity tool) working folder 357 | .mfractor/ 358 | 359 | # Local History for Visual Studio 360 | .localhistory/ 361 | 362 | # BeatPulse healthcheck temp database 363 | healthchecksdb 364 | 365 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 366 | MigrationBackup/ 367 | 368 | # Ionide (cross platform F# VS Code tools) working folder 369 | .ionide/ 370 | 371 | # Fody - auto-generated XML schema 372 | FodyWeavers.xsd -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Chameleon 2 | 3 | ## About this project 4 | 5 | CHPE stands for Compiled Hybrid PE, which contains both x86 (or x86\_64) code and Arm64 code. 6 | The special PE files are distributed for reducing the amount of JIT binary translation by `xtajit.dll` (or `xtajit64.dll`). 7 | You can find the more detailed explanations at [Cylance Research Team's Blog](https://blogs.blackberry.com/en/2019/09/teardown-windows-10-on-arm-x86-emulation) and ["WoW64 internals ...re-discovering Heaven's Gate on ARM."](https://wbenny.github.io/2018/11/04/wow64-internals.html) 8 | 9 | These PE files were previously located only at `%SystemRoot%\SysChpe32`. 10 | However, after the introduction of x64 emulation feature, much of the DLLs at `%SystemRoot%\System32` have become a new type of CHPE called CHPEV2 ARM64EC and ARM64X. 11 | 12 | This project collects reverse engineering results of CHPEV2. 13 | 14 | ## Contents 15 | 16 | - [Reverse engineering results of a new relocation entry, `IMAGE_DYNAIC_RELOCATION_ARM64X` in CHPEV2 files](https://ffri.github.io/ProjectChameleon/new_reloc_chpev2/). 17 | - [Ghidra scripts to analyze CHPEV2 files](./ghidra_scripts) 18 | - [A Python script to find CHPE and CHPEV2 files in Windows 10/11 on ARM](./chpe_scanner) 19 | - [PoC code and tools for Hybrid Auxiliary IAT hooking](./hybrid_aux_iat) 20 | - [A Python script for analyzing and modifying `IMAGE_DYNAMIC_RELOCATION_ARM64X`](./arm64x_reloc_tools) 21 | - [Handmade `GetProcAddress` to get the native "#..." arm64 function](./arm64ec_dllimport) (Thanks @DavidXanatos) 22 | 23 | ## Why "Chameleon" ? 24 | 25 | This is because "VsDevCmd.bat" has the "-chameleon" compile flag for building CHPEV2 ARM64EC files. 26 | 27 | ![chameleon compile flag in VsDevCmd.bat](./assets/chameleon.PNG) 28 | 29 | ## Author 30 | 31 | Koh M. Nakagawa. © FFRI Security, Inc. 2021 32 | 33 | ## License 34 | 35 | [Apache version 2.0](./LICENSE) 36 | 37 | -------------------------------------------------------------------------------- /arm64ec_dllimport/README.md: -------------------------------------------------------------------------------- 1 | # What is this 2 | 3 | Its a hand made GetProcAddress which allows to get exported function addresses from x64 (or arm64ec) processes running on arm64 windows. 4 | When applied to a native arm64 process the result is same as from LdrGetProcedureAddress i.e. it returns the normal native export. 5 | Howe ever when called upon a x64 or arm64ec process it returns the result form the alternative export table namely the "EXP+#..." exports, i.e. the x64 stubs which invoke the native arm64 "#..." function. 6 | When the function name is prefixed with a '#' the provided FindDllExport extracts address the not directly exported native function and returns it. 7 | 8 | This library is suitable for finding entry points for code injection as well as to get function addresses to be used in shell code. 9 | 10 | The provided FindDllBase helper allows to locate the base address of a dll given a part of its path (or name only) in the address space of an other process. 11 | 12 | # Example 13 | 14 | //ntdllBase 0x00007ffa5a7d0000 15 | //0x00007ffa5a811050 {ntdll.dll!LdrLoadDll(void)} 16 | //0x00007ffa5a7d1890 {ntdll.dll!EXP+#LdrLoadDll} 17 | //0x00007ffa5a969920 {ntdll.dll!#LdrLoadDll} 18 | 19 | HMODULE hNtdll = GetModuleHandle(L"ntdll.dll"); 20 | //DWORD64 LLW1 = GetProcAddress(hNtdll, "LdrLoadDll"); 21 | DWORD64 LLW1 = FindDllExport(GetCurrentProcess(), (DWORD64)hNtdll, "LdrLoadDll"); 22 | 23 | DWORD64 ntdllBase = FindDllBase(hProcess, L"\\system32\\ntdll.dll"); 24 | DWORD64 LLW2 = FindDllExport(hProcess, ntdllBase, "LdrLoadDll"); 25 | DWORD64 LLW3 = FindDllExport(hProcess, ntdllBase, "#LdrLoadDll"); 26 | 27 | # Supplementary notes 28 | 29 | The code is prepared to be used with https://github.com/rwfpl/rewolf-wow64ext allowing it to be hosted in a x86 32 bit process, a suitable analogon for 32bit arm needs still to be made. 30 | 31 | 32 | # Author 33 | David Xanatos (C) xanasoft.com 34 | 35 | # License 36 | 37 | Licensed under the Apache License, Version 2.0 (the "License"); 38 | you may not use this file except in compliance with the License. 39 | You may obtain a copy of the License at 40 | 41 | http://www.apache.org/licenses/LICENSE-2.0 42 | 43 | Unless required by applicable law or agreed to in writing, software 44 | distributed under the License is distributed on an "AS IS" BASIS, 45 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 46 | See the License for the specific language governing permissions and 47 | limitations under the License. 48 | 49 | This file can be also used under the therms of the GLP and LGPL licenses. 50 | Whatever floats your boat... 51 | 52 | -------------------------------------------------------------------------------- /arm64ec_dllimport/example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 David Xanatos, xanasoft.com 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * This file can be also used under the therms of the GLP and LGPL licenses. 17 | * Whatever floats your boat... 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | extern "C" { 26 | 27 | NTSYSCALLAPI NTSTATUS NTAPI NtAllocateVirtualMemory( 28 | _In_ HANDLE ProcessHandle, 29 | _Inout_ PVOID* BaseAddress, 30 | _In_ ULONG_PTR ZeroBits, 31 | _Inout_ PSIZE_T RegionSize, 32 | _In_ ULONG AllocationType, 33 | _In_ ULONG Protect 34 | ); 35 | 36 | NTSYSCALLAPI NTSTATUS NTAPI NtReadVirtualMemory( 37 | _In_ HANDLE ProcessHandle, 38 | _In_opt_ PVOID BaseAddress, 39 | _Out_writes_bytes_(BufferSize) PVOID Buffer, 40 | _In_ SIZE_T BufferSize, 41 | _Out_opt_ PSIZE_T NumberOfBytesRead 42 | ); 43 | 44 | 45 | NTSYSCALLAPI NTSTATUS NTAPI NtWriteVirtualMemory( 46 | _In_ HANDLE ProcessHandle, 47 | _In_opt_ PVOID BaseAddress, 48 | _In_reads_bytes_(BufferSize) PVOID Buffer, 49 | _In_ SIZE_T BufferSize, 50 | _Out_opt_ PSIZE_T NumberOfBytesWritten 51 | ); 52 | 53 | NTSYSCALLAPI NTSTATUS NTAPI NtProtectVirtualMemory( 54 | _In_ HANDLE ProcessHandle, 55 | _Inout_ PVOID* BaseAddress, 56 | _Inout_ PSIZE_T RegionSize, 57 | _In_ ULONG NewProtect, 58 | _Out_ PULONG OldProtect 59 | ); 60 | 61 | NTSYSCALLAPI NTSTATUS NTAPI NtFlushInstructionCache( 62 | _In_ HANDLE ProcessHandle, 63 | _In_opt_ PVOID BaseAddress, 64 | _In_ SIZE_T Length 65 | ); 66 | 67 | ULONG64 FindDllBase(HANDLE ProcessHandle, const WCHAR* dll); 68 | DWORD64 FindDllExport(HANDLE hProcess, DWORD64 DllBase, const char* ProcName); 69 | } 70 | 71 | int main() 72 | { 73 | wchar_t prog[MAX_PATH] = L"C:\\windows\\system32\\cmd.exe"; 74 | 75 | STARTUPINFOW si = { 0 }; 76 | PROCESS_INFORMATION pi = { 0 }; 77 | si.cb = sizeof(STARTUPINFO); 78 | if (!CreateProcessW(NULL, prog, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { 79 | fprintf(stderr, "CreateProcess(\"%S\") failed; error code = 0x%08X\n", prog, GetLastError()); 80 | return 1; 81 | } 82 | 83 | DWORD64 ntdllBase = FindDllBase(pi.hProcess, L"ntdll.dll"); 84 | DWORD64 pTargetFunc = FindDllExport(pi.hProcess, ntdllBase, "#LdrInitializeThunk"); 85 | 86 | UCHAR code[24]; 87 | 88 | union 89 | { 90 | PBYTE pB; 91 | PWORD pW; 92 | PDWORD pL; 93 | PDWORD64 pQ; 94 | } ip; 95 | ip.pB = code; 96 | 97 | *ip.pL++ = 0xD43E0000; // brk #0xF000 // ARM 98 | //*ip.pB++ = 0xCC; // int3 // x86/x64 99 | 100 | void* RegionBase = (void*)pTargetFunc; 101 | SIZE_T RegionSize = sizeof(code); 102 | ULONG OldProtect; 103 | NtProtectVirtualMemory(pi.hProcess, &RegionBase, &RegionSize, PAGE_EXECUTE_READWRITE, &OldProtect); 104 | 105 | NtWriteVirtualMemory(pi.hProcess, (void*)pTargetFunc, code, ip.pB - code, NULL); 106 | 107 | NtFlushInstructionCache(pi.hProcess, (void*)pTargetFunc, ip.pB - code); 108 | 109 | if (ResumeThread(pi.hThread) == -1) { 110 | fprintf(stderr, "ResumeThread failed; error code = 0x%08X\n", GetLastError()); 111 | return 1; 112 | } 113 | 114 | CloseHandle(pi.hThread); 115 | CloseHandle(pi.hProcess); 116 | return 0; 117 | } -------------------------------------------------------------------------------- /arm64ec_dllimport/example.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32126.315 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcxproj", "{798E4D8F-618E-41C4-B06D-527209A65AC8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Debug|x64.ActiveCfg = Debug|x64 17 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Debug|x64.Build.0 = Debug|x64 18 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Debug|x86.ActiveCfg = Debug|Win32 19 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Debug|x86.Build.0 = Debug|Win32 20 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Release|x64.ActiveCfg = Release|x64 21 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Release|x64.Build.0 = Release|x64 22 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Release|x86.ActiveCfg = Release|Win32 23 | {798E4D8F-618E-41C4-B06D-527209A65AC8}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {FDC0F1EE-BA5E-4861-A506-68D576FB456D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /arm64ec_dllimport/example.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {798e4d8f-618e-41c4-b06d-527209a65ac8} 25 | example 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | ntdll.lib;%(AdditionalDependencies) 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | ntdll.lib;%(AdditionalDependencies) 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | ntdll.lib;%(AdditionalDependencies) 126 | 127 | 128 | 129 | 130 | Level3 131 | true 132 | true 133 | true 134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | true 136 | 137 | 138 | Console 139 | true 140 | true 141 | true 142 | ntdll.lib;%(AdditionalDependencies) 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /arm64ec_dllimport/example.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | -------------------------------------------------------------------------------- /arm64x_reloc_tools/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/psf/black 5 | rev: 20.8b1 6 | hooks: 7 | - id: black 8 | language_version: python3 9 | - repo: https://github.com/PyCQA/isort 10 | rev: 4.3.21 11 | hooks: 12 | - id: isort 13 | - repo: https://github.com/pre-commit/pre-commit-hooks 14 | rev: v3.2.0 15 | hooks: 16 | - id: trailing-whitespace 17 | - id: end-of-file-fixer 18 | - id: check-yaml 19 | - id: check-added-large-files 20 | -------------------------------------------------------------------------------- /arm64x_reloc_tools/README.md: -------------------------------------------------------------------------------- 1 | # ARM64X relocation tools 2 | 3 | ["ARM64X is the resulting binary from linking ARM64 and ARM64EC objs and libs into one."](https://twitter.com/never_released/status/1371546800067346441) 4 | It can be used by multiple processes (ARM64 native processes, ARM64EC processes, and x64 emulation processes) like a fat binary. 5 | If you are not familiar with ARM64X, please check [our blog post](https://ffri.github.io/ProjectChameleon/new_reloc_chpev2/) for more details. 6 | 7 | This directory contains [a simple python script](main.py) that: 8 | 9 | - [Shows `IMAGE_DYNAMIC_RELOCATION_ARM64X` entries in an ARM64X binary](#show-command) 10 | - [Applies `IMAGE_DYNAMIC_RELOCATION_ARM64X` to an ARM64X binary and save it as a file](#apply-command) 11 | - [Modifies `IMAGE_DYNAMIC_RELOCATION_ARM64X` entries to inject arm64 (or x64) shellcode into an ARM64X binary at runtime.](#inject-command) 12 | 13 | ## Requirements 14 | 15 | - Python 3.8 16 | - [Poetry](https://python-poetry.org/) 17 | 18 | ## Usage 19 | 20 | First, you need to resolve dependencies as follows. 21 | 22 | ``` 23 | $ poetry install 24 | ``` 25 | 26 | Then, you can use three commands. 27 | 28 | ### `show` command 29 | 30 | This command shows `IMAGE_DYNAMIC_RELOCATION_ARM64X` entries and save its result as a JSON file. 31 | 32 | ``` 33 | $ poetry run python main.py show data/ChameleonPacker.exe 34 | CHPE fixup is exported to chpe_fixup.json 35 | $ cat chpe_fixup.json | head -n 30 36 | { 37 | "header": { 38 | "version": 1, 39 | "size": 556, 40 | "symbol": 6, 41 | "fixup_info_size": 544 42 | }, 43 | "blocks": [ 44 | { 45 | "base_offset": 0, 46 | "block_size": 44, 47 | "entries": [ 48 | { 49 | "meta_and_offset": 20724, 50 | "meta": 5, 51 | "offset": 244, 52 | "reloc_entry_data_size": 2, 53 | "size_to_be_written": 2, 54 | "reloc_type": "ASSIGN_VALUE", 55 | "data_to_be_written": 34404 56 | }, 57 | { 58 | "meta_and_offset": 37144, 59 | "meta": 9, 60 | "offset": 280, 61 | "reloc_entry_data_size": 4, 62 | "size_to_be_written": 4, 63 | "reloc_type": "ASSIGN_VALUE", 64 | "data_to_be_written": 36864 65 | }, 66 | ``` 67 | 68 | ### `apply` command 69 | 70 | This command applies `IMAGE_DYNAMIC_RELOCATION_ARM64X` to an ARM64X binary and saves its result as a PE file. 71 | 72 | ``` 73 | $ poetry run python main.py apply data/ChameleonPacker.exe 74 | Patched binary is export to ChameleonPacker.exe_mod 75 | Completed 76 | $ file data/ChameleonPacker.exe 77 | data/ChameleonPacker.exe: PE32+ executable (console) Aarch64, for MS Windows 78 | $ file ChameleonPacker.exe_mod 79 | ChameleonPacker.exe_mod: PE32+ executable (console) x86-64, for MS Windows 80 | ``` 81 | 82 | ### `inject` command 83 | 84 | This command injects shellcode into an ARM64X binary as `IMAGE_DYNAMIC_RELOCATION_ARM64X` relocation entries. 85 | You can use this command to create a packed binary by `IMAGE_DYNAMIC_RELOCATION_ARM64X`. 86 | 87 | ``` 88 | $ poetry run python main.py inject --help 89 | Usage: main.py inject [OPTIONS] SHELLCODE_PATH INPUT_EXE ARCH:[arm64|x64] 90 | [SHELLCODE_ENTRY_OFFSET_HEX] [INJECT_POINT_RVA_HEX] 91 | 92 | Arguments: 93 | SHELLCODE_PATH [required] 94 | INPUT_EXE [required] 95 | ARCH:[arm64|x64] [required] 96 | [SHELLCODE_ENTRY_OFFSET_HEX] [default: 0x00] 97 | [INJECT_POINT_RVA_HEX] 98 | $ poetry run python main.py inject ./data/shellcodex64.bin ./data/ChameleonPacker.exe x64 0x1E0 0x7000 99 | Injection point is set to 0x7000 100 | Load shellcode from ./data/shellcodex64.bin 101 | Convert CHPE fixup entry to raw data 102 | Inject shellcode 103 | Patch entrypoint 104 | rva of x64 entrypoint is 0x2490 105 | Overwrite Hybrid Code Map 106 | Expand relocation section & clear existing relocation entries 107 | Export CHPE fixup header 108 | Export CHPE fixup blocks 109 | Patched binary is export to ChameleonPacker.exe_mod 110 | ``` 111 | 112 | ## Author 113 | 114 | Koh M. Nakagawa. © FFRI Security, Inc. 2021 115 | -------------------------------------------------------------------------------- /arm64x_reloc_tools/data/shellcodearm64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/arm64x_reloc_tools/data/shellcodearm64.bin -------------------------------------------------------------------------------- /arm64x_reloc_tools/data/shellcodex64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/arm64x_reloc_tools/data/shellcodex64.bin -------------------------------------------------------------------------------- /arm64x_reloc_tools/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "arm64x_reloc_tools" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Koh M. Nakagawa "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.8" 9 | lief = "^0.11.5" 10 | typer = "^0.3.2" 11 | 12 | [tool.poetry.dev-dependencies] 13 | mypy = "^0.910" 14 | black = "^21.6b0" 15 | isort = "^5.9.1" 16 | flake8 = "^3.9.2" 17 | flake8-isort = "^4.0.0" 18 | flake8-black = "^0.2.1" 19 | pre-commit = "^2.13.0" 20 | 21 | [build-system] 22 | requires = ["poetry-core>=1.0.0"] 23 | build-backend = "poetry.core.masonry.api" 24 | -------------------------------------------------------------------------------- /assets/chameleon.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/assets/chameleon.PNG -------------------------------------------------------------------------------- /chpe_scanner/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .venv 3 | -------------------------------------------------------------------------------- /chpe_scanner/README.md: -------------------------------------------------------------------------------- 1 | # CHPE scanner 2 | 3 | This script shows the list of CHPE and CHPEV2 files. 4 | 5 | ## Author 6 | 7 | Koh M. Nakagawa. © FFRI Security, Inc. 2021 8 | 9 | ## License 10 | 11 | [Apache version 2.0](../LICENSE) 12 | -------------------------------------------------------------------------------- /chpe_scanner/main.py: -------------------------------------------------------------------------------- 1 | # (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 2 | import os 3 | from enum import Enum 4 | from pathlib import Path 5 | from typing import Optional 6 | 7 | import lief 8 | import typer 9 | 10 | app = typer.Typer() 11 | 12 | 13 | class BinType(Enum): 14 | CHPE = 1 15 | CHPEV2_ARM64EC = 2 16 | CHPEV2_ARM64X = 3 17 | ARM64 = 4 18 | AMD64 = 5 19 | I386 = 6 20 | ARM = 7 21 | ARMNT = 8 22 | THUMB = 9 23 | 24 | @staticmethod 25 | def is_chpe_type(bin_type: "BinType") -> bool: 26 | return ( 27 | (bin_type == BinType.CHPE) 28 | | (bin_type == BinType.CHPEV2_ARM64EC) 29 | | (bin_type == BinType.CHPEV2_ARM64X) 30 | ) 31 | 32 | @staticmethod 33 | def has_metadata_pointer(load_config: lief.PE.LoadConfiguration) -> bool: 34 | return ( 35 | type(load_config) == lief.PE.LoadConfigurationV4 36 | or type(load_config) == lief.PE.LoadConfigurationV5 37 | or type(load_config) == lief.PE.LoadConfigurationV6 38 | or type(load_config) == lief.PE.LoadConfigurationV7 39 | ) 40 | 41 | @staticmethod 42 | def get_chpe_bintype(bin_: lief.PE) -> "BinType": 43 | if ( 44 | not bin_.has_configuration 45 | or (not BinType.has_metadata_pointer(bin_.load_configuration)) 46 | or bin_.load_configuration.hybrid_metadata_pointer == 0 47 | ): 48 | if bin_.header.machine == lief.PE.MACHINE_TYPES.ARM64: 49 | return BinType.ARM64 50 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.AMD64: 51 | return BinType.AMD64 52 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.I386: 53 | return BinType.I386 54 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.ARM: 55 | return BinType.ARM 56 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.ARMNT: 57 | return BinType.ARMNT 58 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.THUMB: 59 | return BinType.THUMB 60 | else: 61 | raise RuntimeError(f"{bin_.name} has an unknown machine type") 62 | 63 | if bin_.header.machine == lief.PE.MACHINE_TYPES.ARM64: 64 | return BinType.CHPEV2_ARM64X 65 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.AMD64: 66 | return BinType.CHPEV2_ARM64EC 67 | elif bin_.header.machine == lief.PE.MACHINE_TYPES.I386: 68 | return BinType.CHPE 69 | else: 70 | raise RuntimeError(f"{bin_.name} is unknown CHPE") 71 | 72 | 73 | def check_chpe_type(path: str) -> Optional[BinType]: 74 | if not os.path.exists(path): 75 | raise RuntimeError(f"{path} is not found") 76 | try: 77 | return BinType.get_chpe_bintype(lief.PE.parse(path)) 78 | except Exception as e: 79 | typer.secho(str(e), err=True, fg=typer.colors.RED) 80 | return None 81 | 82 | 83 | @app.command() 84 | def scan(system_root: str) -> None: 85 | path_root = Path(system_root) 86 | if not path_root.exists(): 87 | typer.secho(f"{system_root} does not exist", err=True, fg=typer.colors.RED) 88 | return 89 | with open("chpe_list.csv", "w") as fout0, open("non_chpe_list.csv", "w") as fout1: 90 | for path_name, _, file_names in os.walk(system_root): 91 | for file_name in file_names: 92 | full_path = os.path.join(path_name, file_name) 93 | if not (full_path.endswith(".dll") or full_path.endswith(".exe")): 94 | continue 95 | bin_type = check_chpe_type(full_path) 96 | if BinType.is_chpe_type(bin_type): 97 | typer.echo(full_path) 98 | fout0.write(full_path + "," + f"{str(bin_type)}" + "\n") 99 | else: 100 | fout1.write(full_path + "," + f"{str(bin_type)}" "\n") 101 | 102 | 103 | if __name__ == "__main__": 104 | app() 105 | -------------------------------------------------------------------------------- /chpe_scanner/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "chpe_scanner" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Koh M. Nakagawa "] 6 | license = "MIT License" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.8" 10 | typer = "^0.3.2" 11 | lief = "0.11.3" 12 | 13 | [tool.poetry.dev-dependencies] 14 | isort = "^5.8.0" 15 | black = "^21.5b0" 16 | 17 | [build-system] 18 | requires = ["poetry-core>=1.0.0"] 19 | build-backend = "poetry.core.masonry.api" 20 | -------------------------------------------------------------------------------- /docs/assets/DATA_DIRECTORY_EXPORT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/DATA_DIRECTORY_EXPORT.PNG -------------------------------------------------------------------------------- /docs/assets/DVRT_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/DVRT_annotated.png -------------------------------------------------------------------------------- /docs/assets/arm64x_disas_0x7000_dynamic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/arm64x_disas_0x7000_dynamic.png -------------------------------------------------------------------------------- /docs/assets/arm64x_disas_0x7000_static.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/arm64x_disas_0x7000_static.png -------------------------------------------------------------------------------- /docs/assets/arm64x_reloc_decoding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/arm64x_reloc_decoding.png -------------------------------------------------------------------------------- /docs/assets/arm64x_reloc_obfus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/arm64x_reloc_obfus.gif -------------------------------------------------------------------------------- /docs/assets/code1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/code1.PNG -------------------------------------------------------------------------------- /docs/assets/code2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/code2.PNG -------------------------------------------------------------------------------- /docs/assets/code3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/code3.PNG -------------------------------------------------------------------------------- /docs/assets/code4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/code4.PNG -------------------------------------------------------------------------------- /docs/assets/code5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/code5.PNG -------------------------------------------------------------------------------- /docs/assets/code6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/code6.PNG -------------------------------------------------------------------------------- /docs/assets/dvrt_user32_structure.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/dvrt_user32_structure.PNG -------------------------------------------------------------------------------- /docs/assets/export_address_table_x64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/export_address_table_x64.PNG -------------------------------------------------------------------------------- /docs/assets/export_func_addr_arm64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/export_func_addr_arm64.PNG -------------------------------------------------------------------------------- /docs/assets/export_func_addr_x64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/export_func_addr_x64.PNG -------------------------------------------------------------------------------- /docs/assets/export_is_different.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/export_is_different.png -------------------------------------------------------------------------------- /docs/assets/for_figure_creation.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/for_figure_creation.pptx -------------------------------------------------------------------------------- /docs/assets/image_section_header.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/image_section_header.PNG -------------------------------------------------------------------------------- /docs/assets/image_sections_after.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/image_sections_after.PNG -------------------------------------------------------------------------------- /docs/assets/image_sections_before.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/image_sections_before.PNG -------------------------------------------------------------------------------- /docs/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/images/favicon.png -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.da.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Danish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.de.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `German` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.du.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Dutch` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.fi.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Finnish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=function(){var e=i.stemmerSupport.Among,r=i.stemmerSupport.SnowballProgram,n=new function(){function i(){f=A.limit,d=f,n()||(f=A.cursor,n()||(d=A.cursor))}function n(){for(var i;;){if(i=A.cursor,A.in_grouping(W,97,246))break;if(A.cursor=i,i>=A.limit)return!0;A.cursor++}for(A.cursor=i;!A.out_grouping(W,97,246);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}function t(){return d<=A.cursor}function s(){var i,e;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(h,10)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.in_grouping_b(x,97,246))return;break;case 2:if(!t())return}A.slice_del()}else A.limit_backward=e}function o(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(v,9))switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"k")||(A.cursor=A.limit-r,A.slice_del());break;case 2:A.slice_del(),A.ket=A.cursor,A.eq_s_b(3,"kse")&&(A.bra=A.cursor,A.slice_from("ksi"));break;case 3:A.slice_del();break;case 4:A.find_among_b(p,6)&&A.slice_del();break;case 5:A.find_among_b(g,6)&&A.slice_del();break;case 6:A.find_among_b(j,2)&&A.slice_del()}else A.limit_backward=e}function l(){return A.find_among_b(q,7)}function a(){return A.eq_s_b(1,"i")&&A.in_grouping_b(L,97,246)}function u(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(C,30)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.eq_s_b(1,"a"))return;break;case 2:case 9:if(!A.eq_s_b(1,"e"))return;break;case 3:if(!A.eq_s_b(1,"i"))return;break;case 4:if(!A.eq_s_b(1,"o"))return;break;case 5:if(!A.eq_s_b(1,"ä"))return;break;case 6:if(!A.eq_s_b(1,"ö"))return;break;case 7:if(r=A.limit-A.cursor,!l()&&(A.cursor=A.limit-r,!A.eq_s_b(2,"ie"))){A.cursor=A.limit-r;break}if(A.cursor=A.limit-r,A.cursor<=A.limit_backward){A.cursor=A.limit-r;break}A.cursor--,A.bra=A.cursor;break;case 8:if(!A.in_grouping_b(W,97,246)||!A.out_grouping_b(W,97,246))return}A.slice_del(),k=!0}else A.limit_backward=e}function c(){var i,e,r;if(A.cursor>=d)if(e=A.limit_backward,A.limit_backward=d,A.ket=A.cursor,i=A.find_among_b(P,14)){if(A.bra=A.cursor,A.limit_backward=e,1==i){if(r=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-r}A.slice_del()}else A.limit_backward=e}function m(){var i;A.cursor>=f&&(i=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.find_among_b(F,2)?(A.bra=A.cursor,A.limit_backward=i,A.slice_del()):A.limit_backward=i)}function w(){var i,e,r,n,t,s;if(A.cursor>=f){if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.eq_s_b(1,"t")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.in_grouping_b(W,97,246)&&(A.cursor=A.limit-r,A.slice_del(),A.limit_backward=e,n=A.limit-A.cursor,A.cursor>=d&&(A.cursor=d,t=A.limit_backward,A.limit_backward=A.cursor,A.cursor=A.limit-n,A.ket=A.cursor,i=A.find_among_b(S,2))))){if(A.bra=A.cursor,A.limit_backward=t,1==i){if(s=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-s}return void A.slice_del()}A.limit_backward=e}}function _(){var i,e,r,n;if(A.cursor>=f){for(i=A.limit_backward,A.limit_backward=f,e=A.limit-A.cursor,l()&&(A.cursor=A.limit-e,A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.in_grouping_b(y,97,228)&&(A.bra=A.cursor,A.out_grouping_b(W,97,246)&&A.slice_del()),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"j")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.eq_s_b(1,"o")?A.slice_del():(A.cursor=A.limit-r,A.eq_s_b(1,"u")&&A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"o")&&(A.bra=A.cursor,A.eq_s_b(1,"j")&&A.slice_del()),A.cursor=A.limit-e,A.limit_backward=i;;){if(n=A.limit-A.cursor,A.out_grouping_b(W,97,246)){A.cursor=A.limit-n;break}if(A.cursor=A.limit-n,A.cursor<=A.limit_backward)return;A.cursor--}A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,b=A.slice_to(),A.eq_v_b(b)&&A.slice_del())}}var k,b,d,f,h=[new e("pa",-1,1),new e("sti",-1,2),new e("kaan",-1,1),new e("han",-1,1),new e("kin",-1,1),new e("hän",-1,1),new e("kään",-1,1),new e("ko",-1,1),new e("pä",-1,1),new e("kö",-1,1)],p=[new e("lla",-1,-1),new e("na",-1,-1),new e("ssa",-1,-1),new e("ta",-1,-1),new e("lta",3,-1),new e("sta",3,-1)],g=[new e("llä",-1,-1),new e("nä",-1,-1),new e("ssä",-1,-1),new e("tä",-1,-1),new e("ltä",3,-1),new e("stä",3,-1)],j=[new e("lle",-1,-1),new e("ine",-1,-1)],v=[new e("nsa",-1,3),new e("mme",-1,3),new e("nne",-1,3),new e("ni",-1,2),new e("si",-1,1),new e("an",-1,4),new e("en",-1,6),new e("än",-1,5),new e("nsä",-1,3)],q=[new e("aa",-1,-1),new e("ee",-1,-1),new e("ii",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1),new e("ää",-1,-1),new e("öö",-1,-1)],C=[new e("a",-1,8),new e("lla",0,-1),new e("na",0,-1),new e("ssa",0,-1),new e("ta",0,-1),new e("lta",4,-1),new e("sta",4,-1),new e("tta",4,9),new e("lle",-1,-1),new e("ine",-1,-1),new e("ksi",-1,-1),new e("n",-1,7),new e("han",11,1),new e("den",11,-1,a),new e("seen",11,-1,l),new e("hen",11,2),new e("tten",11,-1,a),new e("hin",11,3),new e("siin",11,-1,a),new e("hon",11,4),new e("hän",11,5),new e("hön",11,6),new e("ä",-1,8),new e("llä",22,-1),new e("nä",22,-1),new e("ssä",22,-1),new e("tä",22,-1),new e("ltä",26,-1),new e("stä",26,-1),new e("ttä",26,9)],P=[new e("eja",-1,-1),new e("mma",-1,1),new e("imma",1,-1),new e("mpa",-1,1),new e("impa",3,-1),new e("mmi",-1,1),new e("immi",5,-1),new e("mpi",-1,1),new e("impi",7,-1),new e("ejä",-1,-1),new e("mmä",-1,1),new e("immä",10,-1),new e("mpä",-1,1),new e("impä",12,-1)],F=[new e("i",-1,-1),new e("j",-1,-1)],S=[new e("mma",-1,1),new e("imma",0,-1)],y=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],W=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],x=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],A=new r;this.setCurrent=function(i){A.setCurrent(i)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return i(),k=!1,A.limit_backward=e,A.cursor=A.limit,s(),A.cursor=A.limit,o(),A.cursor=A.limit,u(),A.cursor=A.limit,c(),A.cursor=A.limit,k?(m(),A.cursor=A.limit):(A.cursor=A.limit,w(),A.cursor=A.limit),_(),!0}};return function(i){return"function"==typeof i.update?i.update(function(i){return n.setCurrent(i),n.stem(),n.getCurrent()}):(n.setCurrent(i),n.stem(),n.getCurrent())}}(),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.fr.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `French` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,s){return!(!W.eq_s(1,e)||(W.ket=W.cursor,!W.in_grouping(F,97,251)))&&(W.slice_from(r),W.cursor=s,!0)}function i(e,r,s){return!!W.eq_s(1,e)&&(W.ket=W.cursor,W.slice_from(r),W.cursor=s,!0)}function n(){for(var r,s;;){if(r=W.cursor,W.in_grouping(F,97,251)){if(W.bra=W.cursor,s=W.cursor,e("u","U",r))continue;if(W.cursor=s,e("i","I",r))continue;if(W.cursor=s,i("y","Y",r))continue}if(W.cursor=r,W.bra=r,!e("y","Y",r)){if(W.cursor=r,W.eq_s(1,"q")&&(W.bra=W.cursor,i("u","U",r)))continue;if(W.cursor=r,r>=W.limit)return;W.cursor++}}}function t(){for(;!W.in_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}for(;!W.out_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}return!1}function u(){var e=W.cursor;if(q=W.limit,g=q,p=q,W.in_grouping(F,97,251)&&W.in_grouping(F,97,251)&&W.cursor=W.limit){W.cursor=q;break}W.cursor++}while(!W.in_grouping(F,97,251))}q=W.cursor,W.cursor=e,t()||(g=W.cursor,t()||(p=W.cursor))}function o(){for(var e,r;;){if(r=W.cursor,W.bra=r,!(e=W.find_among(h,4)))break;switch(W.ket=W.cursor,e){case 1:W.slice_from("i");break;case 2:W.slice_from("u");break;case 3:W.slice_from("y");break;case 4:if(W.cursor>=W.limit)return;W.cursor++}}}function c(){return q<=W.cursor}function a(){return g<=W.cursor}function l(){return p<=W.cursor}function w(){var e,r;if(W.ket=W.cursor,e=W.find_among_b(C,43)){switch(W.bra=W.cursor,e){case 1:if(!l())return!1;W.slice_del();break;case 2:if(!l())return!1;W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")&&(W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU"));break;case 3:if(!l())return!1;W.slice_from("log");break;case 4:if(!l())return!1;W.slice_from("u");break;case 5:if(!l())return!1;W.slice_from("ent");break;case 6:if(!c())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(z,6))switch(W.bra=W.cursor,e){case 1:l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&W.slice_del()));break;case 2:l()?W.slice_del():a()&&W.slice_from("eux");break;case 3:l()&&W.slice_del();break;case 4:c()&&W.slice_from("i")}break;case 7:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(y,3))switch(W.bra=W.cursor,e){case 1:l()?W.slice_del():W.slice_from("abl");break;case 2:l()?W.slice_del():W.slice_from("iqU");break;case 3:l()&&W.slice_del()}break;case 8:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")))){W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU");break}break;case 9:W.slice_from("eau");break;case 10:if(!a())return!1;W.slice_from("al");break;case 11:if(l())W.slice_del();else{if(!a())return!1;W.slice_from("eux")}break;case 12:if(!a()||!W.out_grouping_b(F,97,251))return!1;W.slice_del();break;case 13:return c()&&W.slice_from("ant"),!1;case 14:return c()&&W.slice_from("ent"),!1;case 15:return r=W.limit-W.cursor,W.in_grouping_b(F,97,251)&&c()&&(W.cursor=W.limit-r,W.slice_del()),!1}return!0}return!1}function f(){var e,r;if(W.cursor=q){if(s=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,e=W.find_among_b(P,7))switch(W.bra=W.cursor,e){case 1:if(l()){if(i=W.limit-W.cursor,!W.eq_s_b(1,"s")&&(W.cursor=W.limit-i,!W.eq_s_b(1,"t")))break;W.slice_del()}break;case 2:W.slice_from("i");break;case 3:W.slice_del();break;case 4:W.eq_s_b(2,"gu")&&W.slice_del()}W.limit_backward=s}}function b(){var e=W.limit-W.cursor;W.find_among_b(U,5)&&(W.cursor=W.limit-e,W.ket=W.cursor,W.cursor>W.limit_backward&&(W.cursor--,W.bra=W.cursor,W.slice_del()))}function d(){for(var e,r=1;W.out_grouping_b(F,97,251);)r--;if(r<=0){if(W.ket=W.cursor,e=W.limit-W.cursor,!W.eq_s_b(1,"é")&&(W.cursor=W.limit-e,!W.eq_s_b(1,"è")))return;W.bra=W.cursor,W.slice_from("e")}}function k(){if(!w()&&(W.cursor=W.limit,!f()&&(W.cursor=W.limit,!m())))return W.cursor=W.limit,void _();W.cursor=W.limit,W.ket=W.cursor,W.eq_s_b(1,"Y")?(W.bra=W.cursor,W.slice_from("i")):(W.cursor=W.limit,W.eq_s_b(1,"ç")&&(W.bra=W.cursor,W.slice_from("c")))}var p,g,q,v=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],h=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],z=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],y=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],C=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],x=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],I=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],P=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],U=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],F=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],S=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],W=new s;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){var e=W.cursor;return n(),W.cursor=e,u(),W.limit_backward=e,W.cursor=W.limit,k(),W.cursor=W.limit,b(),W.cursor=W.limit,d(),W.cursor=W.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.hi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.hu.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Hungarian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,n=L.cursor;if(d=L.limit,L.in_grouping(W,97,252))for(;;){if(e=L.cursor,L.out_grouping(W,97,252))return L.cursor=e,L.find_among(g,8)||(L.cursor=e,e=L.limit)return void(d=e);L.cursor++}if(L.cursor=n,L.out_grouping(W,97,252)){for(;!L.in_grouping(W,97,252);){if(L.cursor>=L.limit)return;L.cursor++}d=L.cursor}}function i(){return d<=L.cursor}function a(){var e;if(L.ket=L.cursor,(e=L.find_among_b(h,2))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e")}}function t(){var e=L.limit-L.cursor;return!!L.find_among_b(p,23)&&(L.cursor=L.limit-e,!0)}function s(){if(L.cursor>L.limit_backward){L.cursor--,L.ket=L.cursor;var e=L.cursor-1;L.limit_backward<=e&&e<=L.limit&&(L.cursor=e,L.bra=e,L.slice_del())}}function c(){var e;if(L.ket=L.cursor,(e=L.find_among_b(_,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function o(){L.ket=L.cursor,L.find_among_b(v,44)&&(L.bra=L.cursor,i()&&(L.slice_del(),a()))}function w(){var e;if(L.ket=L.cursor,(e=L.find_among_b(z,3))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("e");break;case 2:case 3:L.slice_from("a")}}function l(){var e;if(L.ket=L.cursor,(e=L.find_among_b(y,6))&&(L.bra=L.cursor,i()))switch(e){case 1:case 2:L.slice_del();break;case 3:L.slice_from("a");break;case 4:L.slice_from("e")}}function u(){var e;if(L.ket=L.cursor,(e=L.find_among_b(j,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function m(){var e;if(L.ket=L.cursor,(e=L.find_among_b(C,7))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:L.slice_del()}}function k(){var e;if(L.ket=L.cursor,(e=L.find_among_b(P,12))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 9:L.slice_del();break;case 2:case 5:case 8:L.slice_from("e");break;case 3:case 6:L.slice_from("a")}}function f(){var e;if(L.ket=L.cursor,(e=L.find_among_b(F,31))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:L.slice_del();break;case 2:case 5:case 10:case 14:case 19:L.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:L.slice_from("e")}}function b(){var e;if(L.ket=L.cursor,(e=L.find_among_b(S,42))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:L.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:L.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:L.slice_from("e")}}var d,g=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],h=[new n("á",-1,1),new n("é",-1,2)],p=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],_=[new n("al",-1,1),new n("el",-1,2)],v=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],z=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],y=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],j=[new n("á",-1,1),new n("é",-1,2)],C=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],P=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],F=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],S=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var n=L.cursor;return e(),L.limit_backward=n,L.cursor=L.limit,c(),L.cursor=L.limit,o(),L.cursor=L.limit,w(),L.cursor=L.limit,l(),L.cursor=L.limit,u(),L.cursor=L.limit,k(),L.cursor=L.limit,f(),L.cursor=L.limit,b(),L.cursor=L.limit,m(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.ja.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.no.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Norwegian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.pt.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Portuguese` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(k,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("a~");continue;case 2:z.slice_from("o~");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function n(){if(z.out_grouping(y,97,250)){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!0;z.cursor++}return!1}return!0}function i(){if(z.in_grouping(y,97,250))for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return g=z.cursor,!0}function o(){var e,r,s=z.cursor;if(z.in_grouping(y,97,250))if(e=z.cursor,n()){if(z.cursor=e,i())return}else g=z.cursor;if(z.cursor=s,z.out_grouping(y,97,250)){if(r=z.cursor,n()){if(z.cursor=r,!z.in_grouping(y,97,250)||z.cursor>=z.limit)return;z.cursor++}g=z.cursor}}function t(){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return!0}function a(){var e=z.cursor;g=z.limit,b=g,h=g,o(),z.cursor=e,t()&&(b=z.cursor,t()&&(h=z.cursor))}function u(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(q,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("ã");continue;case 2:z.slice_from("õ");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function w(){return g<=z.cursor}function m(){return b<=z.cursor}function c(){return h<=z.cursor}function l(){var e;if(z.ket=z.cursor,!(e=z.find_among_b(F,45)))return!1;switch(z.bra=z.cursor,e){case 1:if(!c())return!1;z.slice_del();break;case 2:if(!c())return!1;z.slice_from("log");break;case 3:if(!c())return!1;z.slice_from("u");break;case 4:if(!c())return!1;z.slice_from("ente");break;case 5:if(!m())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(j,4),e&&(z.bra=z.cursor,c()&&(z.slice_del(),1==e&&(z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del()))));break;case 6:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(C,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 7:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(P,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 8:if(!c())return!1;z.slice_del(),z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del());break;case 9:if(!w()||!z.eq_s_b(1,"e"))return!1;z.slice_from("ir")}return!0}function f(){var e,r;if(z.cursor>=g){if(r=z.limit_backward,z.limit_backward=g,z.ket=z.cursor,e=z.find_among_b(S,120))return z.bra=z.cursor,1==e&&z.slice_del(),z.limit_backward=r,!0;z.limit_backward=r}return!1}function d(){var e;z.ket=z.cursor,(e=z.find_among_b(W,7))&&(z.bra=z.cursor,1==e&&w()&&z.slice_del())}function v(e,r){if(z.eq_s_b(1,e)){z.bra=z.cursor;var s=z.limit-z.cursor;if(z.eq_s_b(1,r))return z.cursor=z.limit-s,w()&&z.slice_del(),!1}return!0}function p(){var e;if(z.ket=z.cursor,e=z.find_among_b(L,4))switch(z.bra=z.cursor,e){case 1:w()&&(z.slice_del(),z.ket=z.cursor,z.limit-z.cursor,v("u","g")&&v("i","c"));break;case 2:z.slice_from("c")}}function _(){if(!l()&&(z.cursor=z.limit,!f()))return z.cursor=z.limit,void d();z.cursor=z.limit,z.ket=z.cursor,z.eq_s_b(1,"i")&&(z.bra=z.cursor,z.eq_s_b(1,"c")&&(z.cursor=z.limit,w()&&z.slice_del()))}var h,b,g,k=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],q=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],j=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],C=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],P=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],F=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],S=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],W=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],L=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],y=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],z=new s;this.setCurrent=function(e){z.setCurrent(e)},this.getCurrent=function(){return z.getCurrent()},this.stem=function(){var r=z.cursor;return e(),z.cursor=r,a(),z.limit_backward=r,z.cursor=z.limit,_(),z.cursor=z.limit,p(),z.cursor=z.limit_backward,u(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.ru.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Russian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,t=new function(){function e(){for(;!W.in_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function t(){for(;!W.out_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function w(){b=W.limit,_=b,e()&&(b=W.cursor,t()&&e()&&t()&&(_=W.cursor))}function i(){return _<=W.cursor}function u(e,n){var r,t;if(W.ket=W.cursor,r=W.find_among_b(e,n)){switch(W.bra=W.cursor,r){case 1:if(t=W.limit-W.cursor,!W.eq_s_b(1,"а")&&(W.cursor=W.limit-t,!W.eq_s_b(1,"я")))return!1;case 2:W.slice_del()}return!0}return!1}function o(){return u(h,9)}function s(e,n){var r;return W.ket=W.cursor,!!(r=W.find_among_b(e,n))&&(W.bra=W.cursor,1==r&&W.slice_del(),!0)}function c(){return s(g,26)}function m(){return!!c()&&(u(C,8),!0)}function f(){return s(k,2)}function l(){return u(P,46)}function a(){s(v,36)}function p(){var e;W.ket=W.cursor,(e=W.find_among_b(F,2))&&(W.bra=W.cursor,i()&&1==e&&W.slice_del())}function d(){var e;if(W.ket=W.cursor,e=W.find_among_b(q,4))switch(W.bra=W.cursor,e){case 1:if(W.slice_del(),W.ket=W.cursor,!W.eq_s_b(1,"н"))break;W.bra=W.cursor;case 2:if(!W.eq_s_b(1,"н"))break;case 3:W.slice_del()}}var _,b,h=[new n("в",-1,1),new n("ив",0,2),new n("ыв",0,2),new n("вши",-1,1),new n("ивши",3,2),new n("ывши",3,2),new n("вшись",-1,1),new n("ившись",6,2),new n("ывшись",6,2)],g=[new n("ее",-1,1),new n("ие",-1,1),new n("ое",-1,1),new n("ые",-1,1),new n("ими",-1,1),new n("ыми",-1,1),new n("ей",-1,1),new n("ий",-1,1),new n("ой",-1,1),new n("ый",-1,1),new n("ем",-1,1),new n("им",-1,1),new n("ом",-1,1),new n("ым",-1,1),new n("его",-1,1),new n("ого",-1,1),new n("ему",-1,1),new n("ому",-1,1),new n("их",-1,1),new n("ых",-1,1),new n("ею",-1,1),new n("ою",-1,1),new n("ую",-1,1),new n("юю",-1,1),new n("ая",-1,1),new n("яя",-1,1)],C=[new n("ем",-1,1),new n("нн",-1,1),new n("вш",-1,1),new n("ивш",2,2),new n("ывш",2,2),new n("щ",-1,1),new n("ющ",5,1),new n("ующ",6,2)],k=[new n("сь",-1,1),new n("ся",-1,1)],P=[new n("ла",-1,1),new n("ила",0,2),new n("ыла",0,2),new n("на",-1,1),new n("ена",3,2),new n("ете",-1,1),new n("ите",-1,2),new n("йте",-1,1),new n("ейте",7,2),new n("уйте",7,2),new n("ли",-1,1),new n("или",10,2),new n("ыли",10,2),new n("й",-1,1),new n("ей",13,2),new n("уй",13,2),new n("л",-1,1),new n("ил",16,2),new n("ыл",16,2),new n("ем",-1,1),new n("им",-1,2),new n("ым",-1,2),new n("н",-1,1),new n("ен",22,2),new n("ло",-1,1),new n("ило",24,2),new n("ыло",24,2),new n("но",-1,1),new n("ено",27,2),new n("нно",27,1),new n("ет",-1,1),new n("ует",30,2),new n("ит",-1,2),new n("ыт",-1,2),new n("ют",-1,1),new n("уют",34,2),new n("ят",-1,2),new n("ны",-1,1),new n("ены",37,2),new n("ть",-1,1),new n("ить",39,2),new n("ыть",39,2),new n("ешь",-1,1),new n("ишь",-1,2),new n("ю",-1,2),new n("ую",44,2)],v=[new n("а",-1,1),new n("ев",-1,1),new n("ов",-1,1),new n("е",-1,1),new n("ие",3,1),new n("ье",3,1),new n("и",-1,1),new n("еи",6,1),new n("ии",6,1),new n("ами",6,1),new n("ями",6,1),new n("иями",10,1),new n("й",-1,1),new n("ей",12,1),new n("ией",13,1),new n("ий",12,1),new n("ой",12,1),new n("ам",-1,1),new n("ем",-1,1),new n("ием",18,1),new n("ом",-1,1),new n("ям",-1,1),new n("иям",21,1),new n("о",-1,1),new n("у",-1,1),new n("ах",-1,1),new n("ях",-1,1),new n("иях",26,1),new n("ы",-1,1),new n("ь",-1,1),new n("ю",-1,1),new n("ию",30,1),new n("ью",30,1),new n("я",-1,1),new n("ия",33,1),new n("ья",33,1)],F=[new n("ост",-1,1),new n("ость",-1,1)],q=[new n("ейше",-1,1),new n("н",-1,2),new n("ейш",-1,1),new n("ь",-1,3)],S=[33,65,8,232],W=new r;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){return w(),W.cursor=W.limit,!(W.cursor=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.sv.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Swedish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.th.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[฀-๿]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.vi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); -------------------------------------------------------------------------------- /docs/assets/javascripts/lunr/min/lunr.zh.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("nodejieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 以 于 上 他 而 后 之 来 及 了 因 下 可 到 由 这 与 也 此 但 并 个 其 已 无 小 我 们 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 从 到 得 打 凡 儿 尔 该 各 给 跟 和 何 还 即 几 既 看 据 距 靠 啦 了 另 么 每 们 嘛 拿 哪 那 您 凭 且 却 让 仍 啥 如 若 使 谁 虽 随 同 所 她 哇 嗡 往 哪 些 向 沿 哟 用 于 咱 则 怎 曾 至 致 着 诸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}}); -------------------------------------------------------------------------------- /docs/assets/ksarm64_h_CHPEV2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/ksarm64_h_CHPEV2.PNG -------------------------------------------------------------------------------- /docs/assets/messageboxa_body_arm64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/messageboxa_body_arm64.PNG -------------------------------------------------------------------------------- /docs/assets/messageboxa_body_junk_x86.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/messageboxa_body_junk_x86.PNG -------------------------------------------------------------------------------- /docs/assets/messageboxa_export_x86.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/messageboxa_export_x86.PNG -------------------------------------------------------------------------------- /docs/assets/messageboxa_exportx86_to_body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/messageboxa_exportx86_to_body.png -------------------------------------------------------------------------------- /docs/assets/messageboxa_impl.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/messageboxa_impl.PNG -------------------------------------------------------------------------------- /docs/assets/ntheader_machine.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/ntheader_machine.PNG -------------------------------------------------------------------------------- /docs/assets/schematic_picture_of_arm64x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/schematic_picture_of_arm64x.png -------------------------------------------------------------------------------- /docs/assets/sharp_function_is_called.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/sharp_function_is_called.png -------------------------------------------------------------------------------- /docs/assets/sharp_messageboxa_exp.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/sharp_messageboxa_exp.PNG -------------------------------------------------------------------------------- /docs/assets/sharp_messageboxa_impl.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/assets/sharp_messageboxa_impl.PNG -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | None 5 | 2022-04-25 6 | daily 7 | 8 | 9 | None 10 | 2022-04-25 11 | daily 12 | 13 | 14 | None 15 | 2022-04-25 16 | daily 17 | 18 | -------------------------------------------------------------------------------- /docs/sitemap.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs/sitemap.xml.gz -------------------------------------------------------------------------------- /docs_src/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Project Chameleon 2 | docs_dir: src 3 | site_dir: ../docs 4 | 5 | nav: 6 | - Top page: 'index.md' 7 | - 'Discovering a new relocation entry of ARM64X in recent Windows 10 on Arm': 'new_reloc_chpev2.md' 8 | - 'Relock 3.0: Relocation-based obfuscation revisited in Windows 11 on Arm': 'arm64x_reloc_obfuscation.md' 9 | 10 | repo_url: https://github.com/FFRI/ProjectChameleon 11 | edit_uri: edit/main/docs_src/src/ 12 | 13 | theme: 14 | name: material 15 | 16 | markdown_extensions: 17 | - codehilite 18 | - footnotes 19 | - attr_list 20 | - toc: 21 | permalink: true 22 | - pymdownx.magiclink 23 | -------------------------------------------------------------------------------- /docs_src/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "docs_src" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["Koh M. Nakagawa "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.8" 9 | mkdocs = "^1.1.2" 10 | mkdocs-material = "^7.1.5" 11 | 12 | [tool.poetry.dev-dependencies] 13 | 14 | [build-system] 15 | requires = ["poetry-core>=1.0.0"] 16 | build-backend = "poetry.core.masonry.api" 17 | -------------------------------------------------------------------------------- /docs_src/src/assets/DATA_DIRECTORY_EXPORT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/DATA_DIRECTORY_EXPORT.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/DVRT_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/DVRT_annotated.png -------------------------------------------------------------------------------- /docs_src/src/assets/arm64x_disas_0x7000_dynamic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/arm64x_disas_0x7000_dynamic.png -------------------------------------------------------------------------------- /docs_src/src/assets/arm64x_disas_0x7000_static.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/arm64x_disas_0x7000_static.png -------------------------------------------------------------------------------- /docs_src/src/assets/arm64x_reloc_decoding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/arm64x_reloc_decoding.png -------------------------------------------------------------------------------- /docs_src/src/assets/arm64x_reloc_obfus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/arm64x_reloc_obfus.gif -------------------------------------------------------------------------------- /docs_src/src/assets/code1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/code1.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/code2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/code2.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/code3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/code3.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/code4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/code4.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/code5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/code5.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/code6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/code6.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/dvrt_user32_structure.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/dvrt_user32_structure.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/export_address_table_x64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/export_address_table_x64.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/export_func_addr_arm64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/export_func_addr_arm64.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/export_func_addr_x64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/export_func_addr_x64.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/export_is_different.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/export_is_different.png -------------------------------------------------------------------------------- /docs_src/src/assets/for_figure_creation.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/for_figure_creation.pptx -------------------------------------------------------------------------------- /docs_src/src/assets/image_section_header.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/image_section_header.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/image_sections_after.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/image_sections_after.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/image_sections_before.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/image_sections_before.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/ksarm64_h_CHPEV2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/ksarm64_h_CHPEV2.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/messageboxa_body_arm64.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/messageboxa_body_arm64.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/messageboxa_body_junk_x86.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/messageboxa_body_junk_x86.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/messageboxa_export_x86.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/messageboxa_export_x86.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/messageboxa_exportx86_to_body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/messageboxa_exportx86_to_body.png -------------------------------------------------------------------------------- /docs_src/src/assets/messageboxa_impl.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/messageboxa_impl.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/ntheader_machine.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/ntheader_machine.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/schematic_picture_of_arm64x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/schematic_picture_of_arm64x.png -------------------------------------------------------------------------------- /docs_src/src/assets/sharp_function_is_called.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/sharp_function_is_called.png -------------------------------------------------------------------------------- /docs_src/src/assets/sharp_messageboxa_exp.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/sharp_messageboxa_exp.PNG -------------------------------------------------------------------------------- /docs_src/src/assets/sharp_messageboxa_impl.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/docs_src/src/assets/sharp_messageboxa_impl.PNG -------------------------------------------------------------------------------- /docs_src/src/index.md: -------------------------------------------------------------------------------- 1 | # Project Chameleon 2 | 3 | - [Discovering a new relocation entry of ARM64X in recent Windows 10 on Arm](new_reloc_chpev2.md) 4 | - [Relock 3.0: Relocation-based obfuscation revisited in Windows 11 on Arm](arm64x_reloc_obfuscation.md) 5 | 6 | ## Author 7 | 8 | Koh M. Nakagawa. © FFRI Security, Inc. 2021 9 | -------------------------------------------------------------------------------- /ghidra_scripts/README.md: -------------------------------------------------------------------------------- 1 | # Ghidra scripts for analyzing CHPEV2 files 2 | 3 | ## [ShowChpeFixup.java](./src/main/java/ShowChpeFixup.java) 4 | 5 | This script shows the relocation entries of an input CHPEV2 file as shown in the following figure. 6 | 7 | ![IMAGE_DYNAIC_RELOCATION_ARM64X](./assets/fixup_records.PNG) 8 | 9 | ## [ApplyChpeFixup.java](./src/main/java/ApplyChpeFixup.java) 10 | 11 | This scirpt applies the relocations by `IMAGE_DYNAIC_RELOCATION_ARM64X` to a CHPEV2 file, and saves the applied result as a new file. 12 | 13 | NOTE: this script changes the contents of 1. the PE header 2. code in the text section 3. data in the data section. 14 | For example, this script changes `IMAGE_FILE_HEADER.Machine` from AArch64 (0xaa64) 15 | 16 | ![Before relocation entries are applied](./assets/before_reloc.PNG) 17 | 18 | to x86\_64 (0x8664). 19 | 20 | ![After relocation entries are applied](./assets/after_reloc.PNG) 21 | 22 | You can specify an output directory of the relocation-applied CHPEV2 file by this script. 23 | 24 | ![Popup](./assets/popup_after_reloc.PNG) 25 | -------------------------------------------------------------------------------- /ghidra_scripts/assets/after_reloc.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/ghidra_scripts/assets/after_reloc.PNG -------------------------------------------------------------------------------- /ghidra_scripts/assets/before_reloc.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/ghidra_scripts/assets/before_reloc.PNG -------------------------------------------------------------------------------- /ghidra_scripts/assets/fixup_records.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/ghidra_scripts/assets/fixup_records.PNG -------------------------------------------------------------------------------- /ghidra_scripts/assets/popup_after_reloc.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/ghidra_scripts/assets/popup_after_reloc.PNG -------------------------------------------------------------------------------- /ghidra_scripts/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation 'org.jetbrains:annotations:20.1.0' 3 | }// Builds a Ghidra Extension for a given Ghidra installation. 4 | // 5 | // An absolute path to the Ghidra installation directory must be supplied either by setting the 6 | // GHIDRA_INSTALL_DIR environment variable or Gradle project property: 7 | // 8 | // > export GHIDRA_INSTALL_DIR= 9 | // > gradle 10 | // 11 | // or 12 | // 13 | // > gradle -PGHIDRA_INSTALL_DIR= 14 | // 15 | // Gradle should be invoked from the directory of the project to build. Please see the 16 | // application.gradle.version property in /Ghidra/application.properties 17 | // for the correction version of Gradle to use for the Ghidra installation you specify. 18 | 19 | //----------------------START "DO NOT MODIFY" SECTION------------------------------ 20 | def ghidraInstallDir 21 | 22 | if (System.env.GHIDRA_INSTALL_DIR) { 23 | ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR 24 | } 25 | else if (project.hasProperty("GHIDRA_INSTALL_DIR")) { 26 | ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR") 27 | } 28 | 29 | if (ghidraInstallDir) { 30 | apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle" 31 | } 32 | else { 33 | throw new GradleException("GHIDRA_INSTALL_DIR is not defined!") 34 | } 35 | //----------------------END "DO NOT MODIFY" SECTION------------------------------- 36 | -------------------------------------------------------------------------------- /ghidra_scripts/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /ghidra_scripts/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /ghidra_scripts/src/main/java/ApplyChpeFixup.java: -------------------------------------------------------------------------------- 1 | // (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 2 | // Apply CHPE fixup relocation entries 3 | // @author Koh M. Nakagawa 4 | // @category CHPEV2 5 | // @keybinding 6 | // @menupath 7 | // @toolbar 8 | 9 | import chpe.ChpeFixup; 10 | import generic.continues.RethrowContinuesFactory; 11 | import ghidra.app.plugin.assembler.Assemblers; 12 | import ghidra.app.script.GhidraScript; 13 | import ghidra.app.util.bin.MemoryByteProvider; 14 | import ghidra.app.util.bin.format.pe.PortableExecutable; 15 | import ghidra.app.util.exporter.BinaryExporter; 16 | import ghidra.app.util.exporter.ExporterException; 17 | import ghidra.program.model.mem.Memory; 18 | 19 | import ghidra.program.model.mem.MemoryAccessException; 20 | import ghidra.util.exception.CancelledException; 21 | 22 | import java.io.IOException; 23 | import java.util.List; 24 | import java.io.File; 25 | 26 | public class ApplyChpeFixup extends GhidraScript { 27 | 28 | private void applyAllChpeFixups(List chpeFixupBlocks, Memory memory, long imageBase) throws MemoryAccessException, ChpeFixup.BrokenChpeFixupRecord { 29 | printerr("This script changes the contents of 1. PE header 2. code in text section 3. some data section"); 30 | var assembler = Assemblers.getAssembler(currentProgram); 31 | for (final var chpeFixupBlock: chpeFixupBlocks) { 32 | final var baseOffset = chpeFixupBlock.baseOffset; 33 | for (final var chpeFixupRecord: chpeFixupBlock.records) { 34 | final var addrToBeRelocated = toAddr(chpeFixupRecord.offset + baseOffset + imageBase); 35 | chpeFixupRecord.applyFixup(memory, addrToBeRelocated, assembler); 36 | } 37 | } 38 | } 39 | 40 | private void exportCurrentProgram() throws IOException, ExporterException, CancelledException { 41 | var dir = askDirectory("Please choose a directory to export this modified binary", "Select"); 42 | var fout = new File(dir, currentProgram.getName() + ".x64"); 43 | var exporter = new BinaryExporter(); 44 | exporter.export(fout, currentProgram, currentProgram.getMemory(), getMonitor()); 45 | popup("Relocation applied binary is exported to " + fout.getAbsolutePath() + "."); 46 | } 47 | 48 | public void run() throws Exception { 49 | var provider = new MemoryByteProvider( 50 | currentProgram.getMemory(), currentProgram.getImageBase() 51 | ); 52 | 53 | PortableExecutable peObj; 54 | try { 55 | peObj = PortableExecutable.createPortableExecutable( 56 | RethrowContinuesFactory.INSTANCE, 57 | provider, 58 | PortableExecutable.SectionLayout.MEMORY, 59 | false, 60 | false 61 | ); 62 | } catch (Exception e) { 63 | printerr(e.toString()); 64 | printerr("Is this file really a PE file?"); 65 | return; 66 | } 67 | 68 | final var chpeFixupBlocks = ChpeFixup.getChpeFixupBlocks(peObj, currentProgram, getMonitor()); 69 | applyAllChpeFixups(chpeFixupBlocks, currentProgram.getMemory(), currentProgram.getImageBase().getOffset()); 70 | exportCurrentProgram(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ghidra_scripts/src/main/java/ShowChpeFixup.java: -------------------------------------------------------------------------------- 1 | // (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 2 | // Show CHPE fixup relocation entries 3 | // @author Koh M. Nakagawa 4 | // @category CHPEV2 5 | // @keybinding 6 | // @menupath 7 | // @toolbar 8 | 9 | import com.google.gson.Gson; 10 | import com.google.gson.GsonBuilder; 11 | import ghidra.app.script.GhidraScript; 12 | import generic.continues.RethrowContinuesFactory; 13 | import ghidra.app.util.bin.MemoryByteProvider; 14 | import ghidra.app.util.bin.format.pe.*; 15 | import ghidra.app.tablechooser.*; 16 | import ghidra.program.model.address.Address; 17 | 18 | import java.io.File; 19 | import java.io.FileWriter; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Optional; 23 | 24 | import chpe.ChpeFixup; 25 | 26 | public class ShowChpeFixup extends GhidraScript { 27 | 28 | private static class ChpeFixupRecordsTableElem implements AddressableRowObject { 29 | 30 | public Address location; 31 | public Optional dataBeWritten; 32 | public int metaAndOffset; 33 | public int dataSize; 34 | public Address relocEntryLocation; 35 | public ChpeFixup.ChpeFixupRelocType type; 36 | 37 | ChpeFixupRecordsTableElem(Address location_, 38 | Optional dataBeWritten_, 39 | int metaAndOffset_, 40 | int dataSize_, 41 | Address relocEntryLocation_, 42 | ChpeFixup.ChpeFixupRelocType type_) { 43 | location = location_; 44 | dataBeWritten = dataBeWritten_; 45 | metaAndOffset = metaAndOffset_; 46 | relocEntryLocation = relocEntryLocation_; 47 | dataSize = dataSize_; 48 | type = type_; 49 | } 50 | 51 | @Override 52 | public Address getAddress() { 53 | return location; 54 | } 55 | } 56 | 57 | private static class DataBeWrittenColumn extends StringColumnDisplay { 58 | 59 | @Override 60 | public String getColumnValue(AddressableRowObject addressableRowObject) { 61 | final var elem = (ChpeFixupRecordsTableElem)addressableRowObject; 62 | if (elem.dataBeWritten.isPresent()) { 63 | if (elem.dataSize == 2) { 64 | return Integer.toUnsignedString(elem.dataBeWritten.get().intValue(), 16); 65 | } else if (elem.dataSize == 4) { 66 | return Integer.toUnsignedString(elem.dataBeWritten.get().intValue(), 16); 67 | } else if (elem.dataSize == 8) { 68 | return Long.toUnsignedString(elem.dataBeWritten.get(), 16); 69 | } else { 70 | return "Error! This value should be power of 2."; 71 | } 72 | } else { 73 | return "None"; 74 | } 75 | } 76 | 77 | @Override 78 | public String getColumnName() { 79 | return "Data be written"; 80 | } 81 | } 82 | 83 | private static class MetadataAndOffsetColumn extends StringColumnDisplay { 84 | @Override 85 | public String getColumnValue(AddressableRowObject addressableRowObject) { 86 | final var elem = (ChpeFixupRecordsTableElem)addressableRowObject; 87 | return Long.toHexString(elem.metaAndOffset); 88 | } 89 | 90 | @Override 91 | public String getColumnName() { 92 | return "Metadata and Offset"; 93 | } 94 | } 95 | 96 | private static class RelocEntryLocation extends AbstractColumnDisplay
{ 97 | @Override 98 | public Address getColumnValue(AddressableRowObject addressableRowObject) { 99 | final var elem = (ChpeFixupRecordsTableElem)addressableRowObject; 100 | return elem.relocEntryLocation; 101 | } 102 | 103 | @Override 104 | public String getColumnName() { 105 | return "Relocation Entry Location"; 106 | } 107 | 108 | @Override 109 | public int compare(AddressableRowObject o1, AddressableRowObject o2) { 110 | final var o1Elem = (ChpeFixupRecordsTableElem)o1; 111 | final var o2Elem = (ChpeFixupRecordsTableElem)o2; 112 | return o1Elem.relocEntryLocation.compareTo(o2Elem.relocEntryLocation); 113 | } 114 | } 115 | 116 | private static class RelocEntryType extends StringColumnDisplay { 117 | @Override 118 | public String getColumnValue(AddressableRowObject addressableRowObject) { 119 | final var elem = (ChpeFixupRecordsTableElem)addressableRowObject; 120 | return elem.type.toString(); 121 | } 122 | 123 | @Override 124 | public String getColumnName() { 125 | return "Relocation Type"; 126 | } 127 | } 128 | 129 | private void configureTableColumns(TableChooserDialog tableDialog) { 130 | tableDialog.addCustomColumn(new DataBeWrittenColumn()); 131 | tableDialog.addCustomColumn(new MetadataAndOffsetColumn()); 132 | tableDialog.addCustomColumn(new RelocEntryLocation()); 133 | tableDialog.addCustomColumn(new RelocEntryType()); 134 | } 135 | 136 | private void showAsTable(List chpeFixupBlocks, TableChooserDialog tableDialog, long imageBase) { 137 | for (final var chpeFixupBlock: chpeFixupBlocks) { 138 | final var baseOffset = chpeFixupBlock.baseOffset; 139 | for (final var chpeFixupRecord: chpeFixupBlock.records) { 140 | final var pointToBeRelocated = toAddr(chpeFixupRecord.offset + baseOffset + imageBase); 141 | tableDialog.add( 142 | new ChpeFixupRecordsTableElem( 143 | pointToBeRelocated, 144 | chpeFixupRecord.data(), 145 | chpeFixupRecord.metaAndOffset, 146 | chpeFixupRecord.sizeToBeWritten, 147 | chpeFixupRecord.location, 148 | chpeFixupRecord.relocType 149 | ) 150 | ); 151 | } 152 | } 153 | } 154 | 155 | public void run() throws Exception { 156 | var tableDialog = createTableChooserDialog( 157 | "Show ChpeFixup records of " + currentProgram.getName(), 158 | null); 159 | configureTableColumns(tableDialog); 160 | tableDialog.show(); 161 | 162 | var provider = new MemoryByteProvider( 163 | currentProgram.getMemory(), currentProgram.getImageBase() 164 | ); 165 | 166 | PortableExecutable peObj; 167 | try { 168 | peObj = PortableExecutable.createPortableExecutable( 169 | RethrowContinuesFactory.INSTANCE, 170 | provider, 171 | PortableExecutable.SectionLayout.MEMORY, 172 | false, 173 | false 174 | ); 175 | } catch (Exception e) { 176 | printerr(e.toString()); 177 | printerr("Is this file really PE file?"); 178 | return; 179 | } 180 | 181 | var chpeFixupBlocks = ChpeFixup.getChpeFixupBlocks(peObj, currentProgram, getMonitor()); 182 | showAsTable(chpeFixupBlocks, tableDialog, currentProgram.getImageBase().getOffset()); 183 | 184 | final var exportJson = askYesNo("JSON export", "Would you like to export relocation entries as JSON file?"); 185 | if (exportJson) { 186 | final var dir = askDirectory("Please choose a directory to export this modified binary", "Select"); 187 | final var jsonOut = new File(dir, "chpe_fixup.json"); 188 | 189 | var rawBlocks = new ArrayList(); 190 | for (final var chpeFixupBlock : chpeFixupBlocks) { 191 | rawBlocks.add(new ChpeFixup.ChpeFixupBlockRaw(chpeFixupBlock)); 192 | } 193 | 194 | var gson = new GsonBuilder().setPrettyPrinting().create(); 195 | var writer = new FileWriter(jsonOut); 196 | gson.toJson(rawBlocks.toArray(), writer); 197 | writer.close(); 198 | 199 | popup("Relocation entries are exported to " + jsonOut.toString() + "."); 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /hybrid_aux_iat/HybridAuxIAT.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31613.86 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HybridAuxIATHooking", "HybridAuxIATHooking\HybridAuxIATHooking.vcxproj", "{5D75E561-7EF3-4ED1-B939-C3679855D990}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arm64ecext", "arm64ecext\arm64ecext.vcxproj", "{BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM64 = Debug|ARM64 13 | Debug|ARM64EC = Debug|ARM64EC 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|ARM64 = Release|ARM64 17 | Release|ARM64EC = Release|ARM64EC 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|ARM64.ActiveCfg = Debug|ARM64 23 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|ARM64.Build.0 = Debug|ARM64 24 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC 25 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|ARM64EC.Build.0 = Debug|ARM64EC 26 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|x64.ActiveCfg = Debug|x64 27 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|x64.Build.0 = Debug|x64 28 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|x86.ActiveCfg = Debug|Win32 29 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Debug|x86.Build.0 = Debug|Win32 30 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|ARM64.ActiveCfg = Release|ARM64EC 31 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|ARM64.Build.0 = Release|ARM64EC 32 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|ARM64EC.ActiveCfg = Release|ARM64EC 33 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|ARM64EC.Build.0 = Release|ARM64EC 34 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|x64.ActiveCfg = Release|x64 35 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|x64.Build.0 = Release|x64 36 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|x86.ActiveCfg = Release|Win32 37 | {5D75E561-7EF3-4ED1-B939-C3679855D990}.Release|x86.Build.0 = Release|Win32 38 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Debug|ARM64.ActiveCfg = Debug|Win32 39 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Debug|ARM64EC.ActiveCfg = Debug|Win32 40 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Debug|x64.ActiveCfg = Debug|x64 41 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Debug|x64.Build.0 = Debug|x64 42 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Debug|x86.ActiveCfg = Debug|Win32 43 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Debug|x86.Build.0 = Debug|Win32 44 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|ARM64.ActiveCfg = Release|ARM64 45 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|ARM64.Build.0 = Release|ARM64 46 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|ARM64EC.ActiveCfg = Release|ARM64 47 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|x64.ActiveCfg = Release|x64 48 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|x64.Build.0 = Release|x64 49 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|x86.ActiveCfg = Release|Win32 50 | {BF6F6CE4-902F-4A5E-AF2B-EE5ECCC47EC6}.Release|x86.Build.0 = Release|Win32 51 | EndGlobalSection 52 | GlobalSection(SolutionProperties) = preSolution 53 | HideSolutionNode = FALSE 54 | EndGlobalSection 55 | GlobalSection(ExtensibilityGlobals) = postSolution 56 | SolutionGuid = {B35987CA-A1A1-4DA1-9972-4BF27E882262} 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /hybrid_aux_iat/HybridAuxIATHooking/.clang-format: -------------------------------------------------------------------------------- 1 | # Visual Studio で生成された .clang-format ファイル 2 | 3 | # このファイル内のスタイルのオプションは、[ツール] > [オプション] から 4 | # 現在の IDE 書式設定を複製しようとします。ただし、次のスタイルの 5 | # オプションを検証する必要があります: 6 | # AfterClass, AfterControlStatement, AfterEnum, AfterFunction, AfterNamespace, 7 | # AfterStruct, AfterUnion 8 | 9 | AccessModifierOffset: -4 10 | AlignAfterOpenBracket: DontAlign 11 | AllowShortBlocksOnASingleLine: true 12 | AllowShortFunctionsOnASingleLine: All 13 | BasedOnStyle: LLVM 14 | BraceWrapping: 15 | AfterClass: false 16 | AfterControlStatement: Never 17 | AfterEnum: true 18 | AfterFunction: false 19 | AfterNamespace: false 20 | AfterStruct: false 21 | AfterUnion: false 22 | BeforeCatch: true 23 | BeforeElse: true 24 | IndentBraces: false 25 | SplitEmptyFunction: true 26 | SplitEmptyRecord: true 27 | BreakBeforeBraces: Custom 28 | ColumnLimit: 0 29 | Cpp11BracedListStyle: false 30 | FixNamespaceComments: false 31 | IndentCaseLabels: false 32 | IndentPPDirectives: None 33 | IndentWidth: 4 34 | MaxEmptyLinesToKeep: 10 35 | NamespaceIndentation: All 36 | PointerAlignment: Left 37 | SortIncludes: false 38 | SortUsingDeclarations: false 39 | SpaceAfterCStyleCast: false 40 | SpaceBeforeAssignmentOperators: true 41 | SpaceBeforeParens: ControlStatements 42 | SpaceInEmptyParentheses: false 43 | SpacesInCStyleCastParentheses: false 44 | SpacesInParentheses: false 45 | SpacesInSquareBrackets: false 46 | TabWidth: 4 47 | UseTab: true 48 | -------------------------------------------------------------------------------- /hybrid_aux_iat/HybridAuxIATHooking/HybridAuxIATHooking.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | ソース ファイル 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /hybrid_aux_iat/HybridAuxIATHooking/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #pragma comment(lib, "dbghelp.lib") 10 | 11 | struct CHPEMetadata { 12 | uint32_t Version; 13 | uint32_t RvaOfHybridCodeMap; 14 | uint32_t NumberOfHybridCodeMap; 15 | uint32_t RvaOfX64CodeRangesToEntryPoints; 16 | uint32_t RvaOfArm64xRedirectionMetadata; 17 | uint32_t RvaOfOsArm64xDispatchCallNoRedirect; 18 | uint32_t RvaOfOsArm64xDispatchRet; 19 | uint32_t RvaOfOsArm64xDispatchCall; 20 | uint32_t RvaOfOsArm64xDispatchICall; 21 | uint32_t RvaOfOsArm64xDispatchICallCfg; 22 | uint32_t RvaOfX64EntryPoint; 23 | uint32_t RvaOfHybridAuxiliaryIat; // 0x2c 24 | uint32_t Field_0x30; 25 | uint32_t Field_0x34; 26 | uint32_t RvaOfOsArm64xRdtsc; 27 | uint32_t RvaOfOsArm64xCpuidex; 28 | uint32_t Field_0x40; 29 | uint32_t Field_0x44r; 30 | uint32_t RvaOfOsArm64xDispatchFptr; 31 | uint32_t RvaOfHybridAuxiliaryIatCopy; 32 | }; 33 | 34 | CHPEMetadata* GetChpeMetadata(HMODULE imageBase) { 35 | ULONG size = 0; 36 | PIMAGE_LOAD_CONFIG_DIRECTORY64 loadConfigDir = (PIMAGE_LOAD_CONFIG_DIRECTORY64)ImageDirectoryEntryToData( 37 | imageBase, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size); 38 | if (!loadConfigDir) { 39 | fprintf(stderr, "Cannt find load configuration directory\n"); 40 | return NULL; 41 | } 42 | fprintf(stdout, "Image Base: %llx\nVA of CHPEMetadata: %llx\nRVA of CHPEMetadata: %llx\n", 43 | (ULONGLONG)imageBase, 44 | loadConfigDir->CHPEMetadataPointer, 45 | (ULONGLONG)loadConfigDir->CHPEMetadataPointer - (ULONGLONG)imageBase); 46 | 47 | return (CHPEMetadata*)loadConfigDir->CHPEMetadataPointer; 48 | } 49 | 50 | ULONGLONG GetIatBaseAddress( 51 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc, 52 | ULONGLONG imageBase) { 53 | ULONGLONG baseAddr = 0xffffffffffffffff; 54 | for (PIMAGE_IMPORT_DESCRIPTOR iter = imageImportDesc; iter->Name != NULL; iter++) { 55 | auto imageThunk = (iter->FirstThunk + imageBase); 56 | if (imageThunk < baseAddr) { 57 | baseAddr = imageThunk; 58 | } 59 | } 60 | return baseAddr; 61 | } 62 | 63 | ULONGLONG IatToHybridAuxIat( 64 | PIMAGE_THUNK_DATA thunk, 65 | ULONGLONG iatBaseAddr, 66 | ULONGLONG hybridAuxIatVA) { 67 | auto delta = (ULONGLONG)thunk - iatBaseAddr; 68 | return hybridAuxIatVA + delta; 69 | } 70 | 71 | void DumpAuxilaryIat( 72 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc, 73 | ULONGLONG imageBase, 74 | ULONGLONG iatBaseAddr, 75 | ULONGLONG hybridAuxIatVA) { 76 | for (PIMAGE_IMPORT_DESCRIPTOR iter = imageImportDesc; iter->Name != NULL; iter++) { 77 | auto dllName = (CHAR*)(iter->Name + imageBase); 78 | printf("DLL Name: %s\n", dllName); 79 | auto imageThunkIat = (PIMAGE_THUNK_DATA)(iter->FirstThunk + imageBase); 80 | auto imageThunkInt = (PIMAGE_THUNK_DATA)(iter->OriginalFirstThunk + imageBase); 81 | do { 82 | if (IMAGE_SNAP_BY_ORDINAL64(imageThunkInt->u1.Ordinal)) { 83 | printf("Ordinal: %llx (IAT entry RVA: %llx) (AuxIAT entry RVA: %llx)\n", 84 | imageThunkInt->u1.Ordinal, 85 | (ULONGLONG)imageThunkIat - imageBase, 86 | IatToHybridAuxIat(imageThunkIat, iatBaseAddr, hybridAuxIatVA) - imageBase); 87 | } 88 | else { 89 | auto imageImportByName = (PIMAGE_IMPORT_BY_NAME)(imageThunkInt->u1.AddressOfData + imageBase); 90 | printf("Name: %s (IAT entry RVA: %llx) (AuxIAT entry RVA: %llx)\n", 91 | imageImportByName->Name, 92 | (ULONGLONG)imageThunkIat - imageBase, 93 | IatToHybridAuxIat(imageThunkIat, iatBaseAddr, hybridAuxIatVA) - imageBase); 94 | } 95 | imageThunkIat++; 96 | imageThunkInt++; 97 | } while (imageThunkIat->u1.AddressOfData); 98 | puts(""); 99 | } 100 | } 101 | 102 | PIMAGE_THUNK_DATA FindIatEntry( 103 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc, 104 | ULONGLONG imageBase, 105 | const CHAR* targetFuncName) { 106 | for (PIMAGE_IMPORT_DESCRIPTOR iter = imageImportDesc; iter->Name != NULL; iter++) { 107 | auto imageThunkIat = (PIMAGE_THUNK_DATA)(iter->FirstThunk + imageBase); 108 | auto imageThunkInt = (PIMAGE_THUNK_DATA)(iter->OriginalFirstThunk + imageBase); 109 | do { 110 | if (!IMAGE_SNAP_BY_ORDINAL64(imageThunkInt->u1.Ordinal)) { 111 | auto imageImportByName = (PIMAGE_IMPORT_BY_NAME)(imageThunkInt->u1.AddressOfData + imageBase); 112 | if (strcmp(targetFuncName, imageImportByName->Name) == 0) { 113 | return imageThunkIat; 114 | } 115 | } 116 | imageThunkIat++; 117 | imageThunkInt++; 118 | } while (imageThunkIat->u1.AddressOfData); 119 | } 120 | return NULL; 121 | } 122 | 123 | PIMAGE_THUNK_DATA FindAuxiliaryIatEntry( 124 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc, 125 | ULONGLONG imageBase, 126 | ULONGLONG iatBaseAddr, 127 | ULONGLONG hybridAuxIatVA, 128 | const CHAR* targetFuncName) { 129 | return (PIMAGE_THUNK_DATA)IatToHybridAuxIat(FindIatEntry(imageImportDesc, imageBase, targetFuncName), iatBaseAddr, hybridAuxIatVA); 130 | } 131 | 132 | typedef int(WINAPI* FuncMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); 133 | FuncMessageBoxA originalMessageBoxA = NULL; 134 | 135 | int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { 136 | (void)lpText; 137 | return originalMessageBoxA(hWnd, "Hoooooooked!!!!!!", lpCaption, uType); 138 | } 139 | 140 | void HookHybridAuxiliaryIat(const char* targetFuncName, PVOID myFunc) { 141 | HMODULE imageBase = GetModuleHandleA(NULL); 142 | CHPEMetadata* chpeMetadata = GetChpeMetadata(imageBase); 143 | 144 | ULONG size = 0; 145 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData( 146 | imageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); 147 | if (!imageImportDesc) { 148 | fprintf(stderr, "Cannot find image import descriptor\n"); 149 | return; 150 | } 151 | 152 | ULONGLONG hybridAuxIatVA = (ULONGLONG)imageBase + chpeMetadata->RvaOfHybridAuxiliaryIat; 153 | printf("VA of hybridAuxIAT: %llx\n", hybridAuxIatVA); 154 | 155 | ULONGLONG iatBaseAddr = GetIatBaseAddress(imageImportDesc, (ULONGLONG)imageBase); 156 | printf("RVA of IAT base address = %llx\n", iatBaseAddr - (ULONGLONG)imageBase); 157 | 158 | // IAT Hook (it works) 159 | // auto msgBoxThunk = FindIatEntry(imageImportDesc, (ULONGLONG)imageBase, targetFuncName); 160 | 161 | // Auxiary IAT Hook (it also works) 162 | auto msgBoxThunk = FindAuxiliaryIatEntry(imageImportDesc, (ULONGLONG)imageBase, iatBaseAddr, hybridAuxIatVA, targetFuncName); 163 | 164 | originalMessageBoxA = (FuncMessageBoxA)msgBoxThunk->u1.Function; 165 | DWORD oldProtect = 0; 166 | VirtualProtect((LPVOID)msgBoxThunk, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &oldProtect); 167 | msgBoxThunk->u1.AddressOfData = (ULONGLONG)myFunc; 168 | } 169 | 170 | int main() { 171 | MessageBoxA(NULL, "Hello", "Hello", MB_OK); 172 | HookHybridAuxiliaryIat("MessageBoxA", MyMessageBoxA); 173 | MessageBoxA(NULL, "Hello", "Hello", MB_OK); 174 | 175 | return EXIT_SUCCESS; 176 | } -------------------------------------------------------------------------------- /hybrid_aux_iat/README.md: -------------------------------------------------------------------------------- 1 | # PoC code and tools for Hybrid Auxiliary IAT hooking 2 | 3 | This directory collects PoC code and tools for Hybrid Auxiliary IAT hooking. 4 | 5 | - [arm64ecext](#arm64ecext) is a WinDbg extension for analyzing Hybrid Auxiliary IAT of ARM64EC. 6 | - [HybridAuxIATHooking](#HybridAuxIATHooking) is PoC code for Hybrid Auxiliary IAT hooking. 7 | 8 | If you are not familiar with Hybrid Auxiliary IAT and its hooking method, check out [my presentation slides at CODE BLUE 2021]() (slides will be available after my talk.). 9 | 10 | ## Requirements 11 | 12 | - Visual Studio 2019 Preview 13 | - [SDK Insider Preview](https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewSDK) 14 | - NOTE: To download this, you need to be a member of the Windows Insider program. 15 | 16 | You also need to set the active solution platform to ARM64 before building. 17 | 18 | ## arm64ecext 19 | 20 | [arm64ecext](./arm64ecext) is a WinDbg extension for analyzing Hybrid Auxiliary IAT of ARM64EC. 21 | 22 | `!arm64ecext.help` shows the usage of this WinDbg extension. 23 | 24 | ``` 25 | 0:024:ARM64EC> .load arm64ecext 26 | 0:024:ARM64EC> !arm64ecext.help 27 | !dump - dump the Hybrid Auxiliary IAT of a module 28 | !show - show the Hybrid Auxiliary IAT entry of a function 29 | !check - check whether Hybrid Auxiliary IAT hooking is used 30 | ``` 31 | 32 | ### `dump` command 33 | 34 | This command shows the Hybrid Auxiliary IAT entries of a specified module. 35 | 36 | ``` 37 | 0:024:ARM64EC> !arm64ecext.dump powershell 38 | Image Base is 00007ff76cb50000 39 | Image Import Descriptor is 00007ff76cb68224 40 | Image Load Config Directory is 00007ff76cb661b0 41 | Module: OLE32.dll 00007ffc1f550000 42 | Name IAT Aux IAT Aux IAT copy 43 | PropVariantClear 00007ffc1f5527c0 00007ffc1f93ede0 00007ff76cb5c220 44 | CoUninitialize 00007ffc1f551af0 00007ffc1f819ae0 00007ff76cb5c320 45 | CoTaskMemAlloc 00007ffc1f5519d0 00007ffc1f81ecf0 00007ff76cb5c260 46 | CoInitializeEx 00007ffc1f5515a0 00007ffc1f8194c0 00007ff76cb5c5a0 47 | CoInitialize 00007ffc20fe1100 00007ffc210db8a0 00007ff76cb5c1e0 48 | CoCreateInstance 00007ffc1f5511c0 00007ffc1f8da770 00007ff76cb5c340 49 | 50 | Module: OLEAUT32.dll 00007ffc20490000 51 | Name IAT Aux IAT Aux IAT copy 52 | Ordinal_9 00007ffc204929b0 00007ffc205ccba0 00007ff76cb5c180 53 | Ordinal_7 00007ffc20491700 00007ffc2058c5d0 00007ff76cb5c360 54 | Ordinal_6 00007ffc204916b0 00007ffc2058c350 00007ff76cb5c4e0 55 | Ordinal_2 00007ffc20491680 00007ffc2058c1d0 00007ff76cb5c480 56 | Ordinal_1a 00007ffc204915d0 00007ffc2058b360 00007ff76cb5c460 57 | Ordinal_f 00007ffc204914c0 00007ffc2058aa10 00007ff76cb5c2e0 58 | 59 | Module: ATL.DLL 00007ffc1acf0000 60 | Name IAT Aux IAT Aux IAT copy 61 | Ordinal_1e 00007ffc1acf10b0 00007ffc1ad05800 00007ff76cb5c140 62 | ... 63 | ``` 64 | 65 | ### `show` command 66 | 67 | This command shows the Hybrid Auxiliary IAT entry of a specified function name. 68 | 69 | ``` 70 | 0:024:ARM64EC> !arm64ecext.show powershell PropVariantClear 71 | Image Base is 00007ff76cb50000 72 | Image Import Descriptor is 00007ff76cb68224 73 | Image Load Config Directory is 00007ff76cb661b0 74 | Name IAT Aux IAT Aux IAT Copy 75 | PropVariantClear 00007ffc1f5527c0 00007ffc1f93ede0 00007ff76cb5c220 76 | ``` 77 | 78 | ### `check` command 79 | 80 | This command shows hooked functions by Hybrid Auxiliary IAT hooking method. 81 | 82 | ``` 83 | 0:000:ARM64EC> !arm64ecext.check AuxiliaryIATHook 84 | Image Base is 00007ff6da6f0000 85 | Image Import Descriptor is 00007ff6da6f7bcc 86 | Image Load Config Directory is 00007ff6da6f72f0 87 | Possibly hooked functions 88 | Name IAT Aux IAT Aux IAT Copy 89 | MessageBoxA 00007ffc20c73190 00007ff6da6f11e0 00007ff6da6f14a0 90 | ``` 91 | 92 | ## HybridAuxIATHooking 93 | 94 | [HybridAuxIATHooking](./HybridAuxIATHooking) is PoC code of Hybrid Auxiliary IAT hooking. 95 | 96 | **Demo movie** 97 | ![Hybrid Auxiliary IAT Hooking Demo](./assets/HybridAuxIATHooking.gif) 98 | 99 | ## Author 100 | 101 | Koh M. Nakagawa. © FFRI Security, Inc. 2021 102 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/.clang-format: -------------------------------------------------------------------------------- 1 | # Visual Studio で生成された .clang-format ファイル 2 | 3 | # このファイル内のスタイルのオプションは、[ツール] > [オプション] から 4 | # 現在の IDE 書式設定を複製しようとします。ただし、次のスタイルの 5 | # オプションを検証する必要があります: 6 | # AfterClass, AfterControlStatement, AfterEnum, AfterFunction, AfterNamespace, 7 | # AfterStruct, AfterUnion 8 | 9 | AccessModifierOffset: -4 10 | AlignAfterOpenBracket: DontAlign 11 | AllowShortBlocksOnASingleLine: true 12 | AllowShortFunctionsOnASingleLine: All 13 | BasedOnStyle: LLVM 14 | BraceWrapping: 15 | AfterClass: false 16 | AfterControlStatement: Never 17 | AfterEnum: true 18 | AfterFunction: false 19 | AfterNamespace: false 20 | AfterStruct: false 21 | AfterUnion: false 22 | BeforeCatch: true 23 | BeforeElse: true 24 | IndentBraces: false 25 | SplitEmptyFunction: true 26 | SplitEmptyRecord: true 27 | BreakBeforeBraces: Custom 28 | ColumnLimit: 0 29 | Cpp11BracedListStyle: false 30 | FixNamespaceComments: false 31 | IndentCaseLabels: false 32 | IndentPPDirectives: None 33 | IndentWidth: 4 34 | MaxEmptyLinesToKeep: 10 35 | NamespaceIndentation: All 36 | PointerAlignment: Left 37 | SortIncludes: false 38 | SortUsingDeclarations: false 39 | SpaceAfterCStyleCast: false 40 | SpaceBeforeAssignmentOperators: true 41 | SpaceBeforeParens: ControlStatements 42 | SpaceInEmptyParentheses: false 43 | SpacesInCStyleCastParentheses: false 44 | SpacesInParentheses: false 45 | SpacesInSquareBrackets: false 46 | TabWidth: 4 47 | UseTab: true 48 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/arm64ecext.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DebugExtensionNotify 3 | DebugExtensionInitialize 4 | DebugExtensionUninitialize 5 | dump 6 | check 7 | show 8 | help 9 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/arm64ecext.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | ヘッダー ファイル 20 | 21 | 22 | ヘッダー ファイル 23 | 24 | 25 | ヘッダー ファイル 26 | 27 | 28 | ヘッダー ファイル 29 | 30 | 31 | ヘッダー ファイル 32 | 33 | 34 | ヘッダー ファイル 35 | 36 | 37 | 38 | 39 | ソース ファイル 40 | 41 | 42 | ソース ファイル 43 | 44 | 45 | ソース ファイル 46 | 47 | 48 | ソース ファイル 49 | 50 | 51 | ソース ファイル 52 | 53 | 54 | ソース ファイル 55 | 56 | 57 | 58 | 59 | 60 | ソース ファイル 61 | 62 | 63 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/chpe_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include "pch.h" 5 | 6 | #include "utils.h" 7 | #include "pe_utils.h" 8 | #include "chpe_utils.h" 9 | 10 | uint32_t GetA64XrmRedirection(const CHPEMetadata* chpeMetadata); 11 | 12 | ULONGLONG IatToHybridAuxIat( 13 | PIMAGE_THUNK_DATA thunk, 14 | ULONGLONG iatBaseAddr, 15 | ULONGLONG hybridAuxIatVA) { 16 | auto delta = (ULONGLONG)thunk - iatBaseAddr; 17 | return hybridAuxIatVA + delta; 18 | } 19 | 20 | RedirectionMap GetModuleRedirectionMap( 21 | ULONGLONG imageBase, 22 | const CHPEMetadata* chpeMetadata) { 23 | DWORD sizeRead = 0; 24 | const auto rvaOfa64xrm = GetA64XrmRedirection(chpeMetadata); 25 | 26 | RedirectionMap a64xrm; 27 | 28 | uint32_t curOffset = 0; 29 | uint32_t x64Rva = 0, arm64Rva = 0; 30 | while (true) { 31 | ReadMemory(imageBase + rvaOfa64xrm + curOffset, &x64Rva, sizeof(uint32_t), &sizeRead); 32 | curOffset += 4; 33 | ReadMemory(imageBase + rvaOfa64xrm + curOffset, &arm64Rva, sizeof(uint32_t), &sizeRead); 34 | curOffset += 4; 35 | if (x64Rva == 0 && arm64Rva == 0) break; 36 | a64xrm[x64Rva] = arm64Rva; 37 | } 38 | return a64xrm; 39 | } 40 | 41 | std::vector CheckHybridAuxIatHooking( 42 | const CHPEImportAddressTables& iats) { 43 | std::vector result; 44 | 45 | for (auto&& modEntry : iats) { 46 | const auto imageLoadConfig = GetLoadConfigDirectory(modEntry.second.imageBase); 47 | const auto chpeMetadata = GetCHPEMetadaPointer(imageLoadConfig); 48 | if (chpeMetadata) { 49 | // NOTE: currently only ARM64EC is supported 50 | auto a64xrm = GetModuleRedirectionMap(modEntry.second.imageBase, chpeMetadata.value()); 51 | for (auto&& funcEntry : modEntry.second.entries) { 52 | const auto vaddrIatRva = (RedirectionMap::key_type)(funcEntry.vaddrIat - modEntry.second.imageBase); 53 | if (a64xrm.contains(vaddrIatRva)) { 54 | const auto exportThunkDest = a64xrm[vaddrIatRva] + modEntry.second.imageBase; 55 | // FastForwarded entry 56 | if (exportThunkDest == funcEntry.vaddrAuxIat) { 57 | continue; 58 | } 59 | // Non-FastForwarded entry 60 | if (funcEntry.vaddrAuxIat == funcEntry.vaddrAuxCopyIat) { 61 | continue; 62 | } 63 | // Suspicious 64 | result.emplace_back(funcEntry); 65 | } 66 | } 67 | } 68 | } 69 | 70 | return result; 71 | } 72 | 73 | std::optional GetCHPEMetadaPointer(PIMAGE_LOAD_CONFIG_DIRECTORY imageLoadConfig) { 74 | CHPEMetadata* chpeMetadata = nullptr; 75 | DWORD sizeRead = 0; 76 | ReadMemory((ULONG64)imageLoadConfig + offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer), 77 | &chpeMetadata, 78 | sizeof(CHPEMetadata*), 79 | &sizeRead); 80 | 81 | if (!chpeMetadata) { 82 | dprintf("CHPEMetadataPointer is NULL, so this module might not be CHPE.\n"); 83 | return std::nullopt; 84 | } 85 | return chpeMetadata; 86 | } 87 | 88 | uint32_t GetA64XrmRedirection(const CHPEMetadata* chpeMetadata) { 89 | uint32_t rvaOfArm64xRedirectionMetadata = 0; 90 | DWORD sizeRead = 0; 91 | ReadMemory((ULONG64)chpeMetadata + offsetof(CHPEMetadata, RvaOfArm64xRedirectionMetadata), 92 | &rvaOfArm64xRedirectionMetadata, 93 | sizeof(uint32_t), 94 | &sizeRead); 95 | return rvaOfArm64xRedirectionMetadata; 96 | } 97 | 98 | uint32_t GetHybridAuxIatRva(const CHPEMetadata* chpeMetadata) { 99 | uint32_t rvaOfHybridAuxIat = 0; 100 | DWORD sizeRead = 0; 101 | ReadMemory((ULONG64)chpeMetadata + offsetof(CHPEMetadata, RvaOfHybridAuxiliaryIat), 102 | &rvaOfHybridAuxIat, 103 | sizeof(uint32_t), 104 | &sizeRead); 105 | return rvaOfHybridAuxIat; 106 | } 107 | 108 | uint32_t GetHybridAuxIatCopyRva(const CHPEMetadata* chpeMetadata) { 109 | uint32_t rvaOfHybridAuxCopyIat = 0; 110 | DWORD sizeRead = 0; 111 | ReadMemory((ULONG64)chpeMetadata + offsetof(CHPEMetadata, RvaOfHybridAuxiliaryIatCopy), 112 | &rvaOfHybridAuxCopyIat, 113 | sizeof(uint32_t), 114 | &sizeRead); 115 | return rvaOfHybridAuxCopyIat; 116 | } 117 | 118 | std::optional GetAllIATs( 119 | ULONGLONG imageBase, 120 | DbgController& dbgCtl) { 121 | const auto imageImportDesc = GetImportDescriptor(imageBase); 122 | dprintf("Image Import Descriptor is %p\n", imageImportDesc); 123 | 124 | const auto imageLoadConfig = GetLoadConfigDirectory(imageBase); 125 | dprintf("Image Load Config Directory is %p\n", imageLoadConfig); 126 | 127 | const auto chpeMetadata = GetCHPEMetadaPointer(imageLoadConfig); 128 | if (!chpeMetadata) { 129 | dprintf("CHPEMetadataPointer is NULL, so this module might not be CHPE.\n"); 130 | return std::nullopt; 131 | } 132 | 133 | const auto hybridAuxIatVA = GetHybridAuxIatRva(chpeMetadata.value()) + imageBase; 134 | const auto hybridAuxIatCopyVa = GetHybridAuxIatCopyRva(chpeMetadata.value()) + imageBase; 135 | const auto iatBaseAddr = GetIatBaseAddress(imageImportDesc, imageBase); 136 | if (!iatBaseAddr) { 137 | dprintf("Failed to IAT base address\n"); 138 | return std::nullopt; 139 | } 140 | 141 | CHPEImportAddressTables iats; 142 | 143 | auto iter = imageImportDesc; 144 | auto modNameRVA = ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, Name)); 145 | while (modNameRVA != NULL) { 146 | auto modName = dbgCtl.ReadAscii(modNameRVA + imageBase); 147 | auto imageThunkIat = 148 | (PIMAGE_THUNK_DATA)(ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, FirstThunk)) + imageBase); 149 | auto imageThunkInt = 150 | (PIMAGE_THUNK_DATA)(ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, OriginalFirstThunk)) + imageBase); 151 | 152 | ImportedModule modInfo; 153 | ULONGLONG addressOfDataIat = 0; 154 | do { 155 | const auto addressOfDataInt = ReadMemberFromStruct(imageThunkInt, offsetof(IMAGE_THUNK_DATA, u1)); 156 | 157 | std::string exportedName; 158 | if (IMAGE_SNAP_BY_ORDINAL(addressOfDataInt)) { 159 | // exported as ordinal 160 | exportedName = "Ordinal_"s + to_hex_string(IMAGE_ORDINAL(addressOfDataInt)); 161 | } else { 162 | // exported as name 163 | const auto imageImportByNameAddr = addressOfDataInt + imageBase; 164 | exportedName = dbgCtl.ReadAscii(imageImportByNameAddr + offsetof(IMAGE_IMPORT_BY_NAME, Name)); 165 | } 166 | ULONG64 iatEntry = 0, auxIatEntry = 0, auxIatCopyEntry = 0; 167 | const auto auxIatEntryAddr = IatToHybridAuxIat(imageThunkIat, iatBaseAddr.value(), hybridAuxIatVA); 168 | const auto auxIatCopyEntryAddr = IatToHybridAuxIat(imageThunkIat, iatBaseAddr.value(), hybridAuxIatCopyVa); 169 | ReadPointer((ULONG64)imageThunkIat, &iatEntry); 170 | ReadPointer((ULONG64)auxIatEntryAddr, &auxIatEntry); 171 | ReadPointer((ULONG64)auxIatCopyEntryAddr, &auxIatCopyEntry); 172 | 173 | modInfo.entries.emplace_back(exportedName, iatEntry, auxIatEntry, auxIatCopyEntry); 174 | 175 | imageThunkIat++; 176 | imageThunkInt++; 177 | 178 | addressOfDataIat = 179 | ReadMemberFromStruct(imageThunkIat, offsetof(IMAGE_THUNK_DATA, u1)); 180 | } while (addressOfDataIat); 181 | 182 | const auto modImageBase = dbgCtl.GetModuleInfo(modInfo.entries.front().vaddrIat); 183 | modInfo.imageBase = modImageBase.base_addr; 184 | iats[modName] = modInfo; 185 | 186 | iter++; 187 | modNameRVA = ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, Name)); 188 | } 189 | 190 | return iats; 191 | } 192 | 193 | void DumpHybridAuxiliaryIat(const CHPEImportAddressTables& iats) { 194 | for (auto&& modEntry : iats) { 195 | dprintf("Module: %s %p\n", modEntry.first.c_str(), modEntry.second.imageBase); 196 | dprintf("%20.20s %16.16s %16.16s %16.16s\n", "Name", "IAT", "Aux IAT", "Aux IAT copy"); 197 | for (auto&& funcEntry : modEntry.second.entries) { 198 | dprintf("%20.20s %p %p %p\n", 199 | funcEntry.name.c_str(), 200 | funcEntry.vaddrIat, 201 | funcEntry.vaddrAuxIat, 202 | funcEntry.vaddrAuxCopyIat); 203 | } 204 | dprintf("\n"); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/chpe_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | struct CHPEMetadata { 10 | uint32_t Version; 11 | uint32_t RvaOfHybridCodeMap; 12 | uint32_t NumberOfHybridCodeMap; 13 | uint32_t RvaOfX64CodeRangesToEntryPoints; 14 | uint32_t RvaOfArm64xRedirectionMetadata; 15 | uint32_t RvaOfOsArm64xDispatchCallNoRedirect; 16 | uint32_t RvaOfOsArm64xDispatchRet; 17 | uint32_t RvaOfOsArm64xDispatchCall; 18 | uint32_t RvaOfOsArm64xDispatchICall; 19 | uint32_t RvaOfOsArm64xDispatchICallCfg; 20 | uint32_t RvaOfX64EntryPoint; 21 | uint32_t RvaOfHybridAuxiliaryIat; 22 | uint32_t Field_0x30; 23 | uint32_t Field_0x34; 24 | uint32_t RvaOfOsArm64xRdtsc; 25 | uint32_t RvaOfOsArm64xCpuidex; 26 | uint32_t Field_0x40; 27 | uint32_t Field_0x44; 28 | uint32_t RvaOfOsArm64xDispatchFptr; 29 | uint32_t RvaOfHybridAuxiliaryIatCopy; 30 | }; 31 | 32 | using RedirectionMap = std::unordered_map; 33 | 34 | struct ImportedFunction { 35 | std::string name; 36 | uint64_t vaddrIat; 37 | uint64_t vaddrAuxIat; 38 | uint64_t vaddrAuxCopyIat; 39 | }; 40 | 41 | struct ImportedModule { 42 | uint64_t imageBase; 43 | std::vector entries; 44 | }; 45 | 46 | using CHPEImportAddressTables = std::unordered_map; 47 | 48 | std::optional GetCHPEMetadaPointer(PIMAGE_LOAD_CONFIG_DIRECTORY imageLoadConfig); 49 | 50 | std::optional GetAllIATs( 51 | ULONGLONG imageBase, 52 | DbgController& dbgctl); 53 | 54 | void DumpHybridAuxiliaryIat(const CHPEImportAddressTables& iats); 55 | 56 | std::vector CheckHybridAuxIatHooking( 57 | const CHPEImportAddressTables& iats); 58 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/dbg_ctl_wrapper.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #pragma once 5 | 6 | using std::system_error; 7 | using std::system_category; 8 | using std::to_string; 9 | using namespace std::literals::string_literals; 10 | 11 | #define THROW_IF_FAIL(EXPR) \ 12 | do {\ 13 | HRESULT err;\ 14 | if ((err = (EXPR)) != S_OK) {\ 15 | throw system_error(std::error_code(err, system_category()), "code is "s + to_string(err) + " at " __FILE__ ":" + to_string(__LINE__));\ 16 | }\ 17 | } while (0) 18 | 19 | #ifdef _DEBUG 20 | #define DEBUG_LOG(...) dbg_ctl_->Output(DEBUG_OUTPUT_NORMAL, __VA_ARGS__) 21 | #else 22 | #define DEBUG_LOG(...) 23 | #endif 24 | 25 | class DbgController final { 26 | template 27 | class DbgDeleter { 28 | public: 29 | void operator()(T* ptr) const { 30 | if (ptr) ptr->Release(); 31 | } 32 | }; 33 | 34 | struct DbgModParams { 35 | uint64_t base_addr = 0; 36 | uint32_t size = 0; 37 | uint32_t time_date_stamp = 0; 38 | uint32_t checksum = 0; 39 | std::string name; 40 | }; 41 | 42 | struct DbgStepResult { 43 | uint64_t pc = 0; 44 | uint32_t insn_size = 0; 45 | }; 46 | 47 | PDEBUG_CLIENT dbg_client_ = nullptr; 48 | std::unique_ptr> dbg_ctl_; 49 | std::unique_ptr> dbg_registers_; 50 | std::unique_ptr> dbg_symbols_; 51 | std::unique_ptr> dbg_data_spaces_; 52 | 53 | uint32_t GetInsnSize(IDebugControl* dbg_ctl, const uint64_t pc) { 54 | uint64_t near_offset = 0; 55 | dbg_ctl->GetNearInstruction(pc, 1, &near_offset); 56 | return static_cast(near_offset - pc); 57 | } 58 | 59 | DbgStepResult DbgStep(const char* step_cmd) { 60 | RunCmd(dbg_ctl_.get(), step_cmd); 61 | const auto pc = GetCurrentPc(); 62 | const auto insn_size = GetInsnSize(dbg_ctl_.get(), pc); 63 | return { 64 | pc, 65 | insn_size 66 | }; 67 | } 68 | 69 | DbgStepResult DbgStepInto() { 70 | return DbgStep("t"); 71 | } 72 | 73 | DbgStepResult DbgStepOver() { 74 | return DbgStep("p"); 75 | } 76 | 77 | void RunCmd(IDebugControl* dbg_ctl, const char* cmd, ULONG timeout = INFINITE) { 78 | THROW_IF_FAIL(dbg_ctl->Execute(DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_OVERRIDE_MASK | DEBUG_OUTCTL_NOT_LOGGED, 79 | cmd, DEBUG_EXECUTE_DEFAULT)); 80 | THROW_IF_FAIL(dbg_ctl->WaitForEvent(0, timeout)); 81 | } 82 | 83 | public: 84 | DbgController(PDEBUG_CLIENT dbg_client) { 85 | dbg_client_ = dbg_client; 86 | 87 | PDEBUG_CONTROL dbg_ctl = nullptr; 88 | PDEBUG_REGISTERS2 dbg_registers = nullptr; 89 | PDEBUG_SYMBOLS3 dbg_symbols = nullptr; 90 | PDEBUG_DATA_SPACES4 dbg_data_spaces = nullptr; 91 | HRESULT err; 92 | if (((err = dbg_client_->QueryInterface(__uuidof(IDebugControl), (void**)&dbg_ctl)) != S_OK) || 93 | ((err = dbg_client_->QueryInterface(__uuidof(IDebugRegisters2), (void**)&dbg_registers)) != S_OK) || 94 | ((err = dbg_client_->QueryInterface(__uuidof(IDebugSymbols3), (void**)&dbg_symbols)) != S_OK) || 95 | ((err = dbg_client_->QueryInterface(__uuidof(IDebugDataSpaces4), (void**)&dbg_data_spaces)) != S_OK)){ 96 | if (dbg_ctl) dbg_ctl->Release(); 97 | if (dbg_registers) dbg_registers->Release(); 98 | if (dbg_symbols) dbg_symbols->Release(); 99 | if (dbg_data_spaces) dbg_data_spaces->Release(); 100 | throw system_error(std::error_code(err, system_category()), "code is "s + to_string(err) + " at " __FILE__ ":" + to_string(__LINE__)); 101 | } 102 | 103 | dbg_ctl_.reset(dbg_ctl); 104 | dbg_registers_.reset(dbg_registers); 105 | dbg_symbols_.reset(dbg_symbols); 106 | dbg_data_spaces_.reset(dbg_data_spaces); 107 | } 108 | 109 | void RunCmd(const char* cmd, ULONG timeout = INFINITE) { 110 | RunCmd(dbg_ctl_.get(), cmd, timeout); 111 | } 112 | 113 | void RunCmdNoWait(const char* cmd) { 114 | THROW_IF_FAIL(dbg_ctl_.get()->Execute(DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_OVERRIDE_MASK | DEBUG_OUTCTL_NOT_LOGGED, 115 | cmd, DEBUG_EXECUTE_DEFAULT)); 116 | } 117 | 118 | std::string ReadAscii(const uint64_t addr) { 119 | char buf[256] {}; 120 | ULONG out_len = 0; 121 | THROW_IF_FAIL(dbg_data_spaces_->ReadMultiByteStringVirtual(addr, sizeof(buf), buf, sizeof(buf), &out_len)); 122 | return buf; 123 | } 124 | 125 | // NOTE: returned data is ASCII 126 | std::string ReadUnicode(const uint64_t addr) { 127 | char buf[256] {}; 128 | ULONG out_len = 0; 129 | THROW_IF_FAIL(dbg_data_spaces_->ReadUnicodeStringVirtual(addr, sizeof(buf), CP_ACP, buf, sizeof(buf), &out_len)); 130 | return buf; 131 | } 132 | 133 | uint64_t GetCurrentPc() { 134 | uint64_t pc = 0; 135 | THROW_IF_FAIL(dbg_registers_->GetInstructionOffset2(DEBUG_REGSRC_DEBUGGEE, &pc)); 136 | return pc; 137 | } 138 | 139 | DbgModParams GetModuleInfo(const uint64_t pc) { 140 | ULONG idx = 0; 141 | uint64_t base_addr = 0; 142 | THROW_IF_FAIL(dbg_symbols_->GetModuleByOffset(pc, 0, &idx, &base_addr)); 143 | 144 | char module_name[MAX_PATH]{}; 145 | ULONG name_size = 0; 146 | THROW_IF_FAIL(dbg_symbols_->GetModuleNameString(DEBUG_MODNAME_IMAGE, idx, base_addr, module_name, sizeof(module_name), &name_size)); 147 | 148 | DEBUG_MODULE_PARAMETERS dbg_mod_params{}; 149 | dbg_symbols_->GetModuleParameters(1, NULL, idx, &dbg_mod_params); 150 | 151 | return { 152 | base_addr, 153 | dbg_mod_params.Size, 154 | dbg_mod_params.TimeDateStamp, 155 | dbg_mod_params.Checksum, 156 | module_name 157 | }; 158 | } 159 | 160 | }; 161 | 162 | #undef THROW_IF_FAIL 163 | #undef DEBUG_LOG -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/dbg_ext_main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include "pch.h" 5 | 6 | #include "utils.h" 7 | #include "pe_utils.h" 8 | #include "chpe_utils.h" 9 | 10 | WINDBG_EXTENSION_APIS ExtensionApis; 11 | 12 | #ifdef _DEBUG 13 | #define DEBUG_LOG(...) ExtensionApis.lpOutputRoutine(__VA_ARGS__) 14 | #else 15 | #define DEBUG_LOG(...) 16 | #endif 17 | 18 | extern "C" { 19 | HRESULT CALLBACK DebugExtensionInitialize(PULONG version, PULONG flags) { 20 | HRESULT hResult; 21 | PDEBUG_CONTROL debugControl; 22 | IDebugClient* debugClient; 23 | 24 | *version = DEBUG_EXTENSION_VERSION(1, 0); 25 | *flags = 0; 26 | hResult = S_OK; 27 | 28 | if ((hResult = DebugCreate(__uuidof(IDebugClient), (void**)&debugClient)) != S_OK) { 29 | return hResult; 30 | } 31 | 32 | if ((hResult = debugClient->QueryInterface(__uuidof(IDebugControl), 33 | (void**)&debugControl)) == S_OK) { 34 | ExtensionApis.nSize = sizeof(ExtensionApis); 35 | hResult = debugControl->GetWindbgExtensionApis64(&ExtensionApis); 36 | debugControl->Release(); 37 | } 38 | debugClient->Release(); 39 | return hResult; 40 | } 41 | 42 | void CALLBACK DebugExtensionUninitialize(void) { 43 | return; 44 | } 45 | 46 | void CALLBACK DebugExtensionNotify(ULONG Notify, ULONG64 Argument) { 47 | UNREFERENCED_PARAMETER(Notify); 48 | UNREFERENCED_PARAMETER(Argument); 49 | } 50 | 51 | HRESULT CALLBACK show(PDEBUG_CLIENT client, PCSTR args) { 52 | DbgController dbgCtl(client); 53 | try { 54 | const auto vargs = get_args(args); 55 | if (vargs.size() != 2) { 56 | dprintf("Usage: !show ImageBase (or ImageName) FunctionName\n"); 57 | return E_FAIL; 58 | } 59 | 60 | const uint64_t imageBase = GetExpression(vargs[0].c_str()); 61 | dprintf("Image Base is %p\n", imageBase); 62 | const auto targetFuncName = vargs[1]; 63 | 64 | const auto iats = GetAllIATs(imageBase, dbgCtl); 65 | if (!iats) { 66 | dprintf("Failed to get IATs\n"); 67 | return E_FAIL; 68 | } 69 | 70 | for (auto&& modEntry : iats.value()) { 71 | for (auto&& funcEntry : modEntry.second.entries) { 72 | if (funcEntry.name.find(targetFuncName) != std::string::npos) { 73 | dprintf("%30.30s %16.16s %16.16s %16.16s\n", 74 | "Name", "IAT", "Aux IAT", "Aux IAT Copy"); 75 | dprintf("%30.30s %p %p %p\n", 76 | funcEntry.name.c_str(), 77 | funcEntry.vaddrIat, 78 | funcEntry.vaddrAuxIat, 79 | funcEntry.vaddrAuxCopyIat); 80 | return S_OK; 81 | } 82 | } 83 | } 84 | 85 | dprintf("%s is not found\n", targetFuncName.c_str()); 86 | return S_OK; 87 | } 88 | catch (const std::system_error& err) { 89 | ExtensionApis.lpOutputRoutine("Error (%s) occured\n", err.what()); 90 | return E_FAIL; 91 | } 92 | catch (const std::runtime_error& err) { 93 | ExtensionApis.lpOutputRoutine("Error (%s) occured\n", err.what()); 94 | return E_FAIL; 95 | } 96 | 97 | } 98 | 99 | HRESULT CALLBACK check(PDEBUG_CLIENT client, PCSTR args) { 100 | DbgController dbgCtl(client); 101 | try { 102 | const auto vargs = get_args(args); 103 | if (vargs.size() != 1) { 104 | dprintf("Usage: !check ImageBase (or ImageName)\n"); 105 | return E_FAIL; 106 | } 107 | 108 | const uint64_t imageBase = GetExpression(vargs[0].c_str()); 109 | dprintf("Image Base is %p\n", imageBase); 110 | 111 | const auto iats = GetAllIATs(imageBase, dbgCtl); 112 | if (!iats) { 113 | dprintf("Failed to get IATs\n"); 114 | return E_FAIL; 115 | } 116 | 117 | const auto hookedFuncs = CheckHybridAuxIatHooking(iats.value()); 118 | if (hookedFuncs.size() == 0) { 119 | dprintf("Hybrid Auxiliary IAT hooked entries are not found.\n"); 120 | return S_OK; 121 | } 122 | dprintf("Possibly hooked Hybrid Auxiliary IAT entries are found.\n"); 123 | dprintf("%30.30s %16.16s %16.16s %16.16s\n", "Name", "IAT", "Aux IAT", "Aux IAT Copy"); 124 | for (auto&& hookedFunc : hookedFuncs) { 125 | dprintf("%30.30s %p %p %p\n", 126 | hookedFunc.name.c_str(), 127 | hookedFunc.vaddrIat, 128 | hookedFunc.vaddrAuxIat, 129 | hookedFunc.vaddrAuxCopyIat); 130 | } 131 | return S_OK; 132 | } 133 | catch (const std::system_error& err) { 134 | ExtensionApis.lpOutputRoutine("Error (%s) occured\n", err.what()); 135 | return E_FAIL; 136 | } 137 | catch (const std::runtime_error& err) { 138 | ExtensionApis.lpOutputRoutine("Error (%s) occured\n", err.what()); 139 | return E_FAIL; 140 | } 141 | } 142 | 143 | HRESULT CALLBACK dump(PDEBUG_CLIENT client, PCSTR args) { 144 | DbgController dbgCtl(client); 145 | try { 146 | const auto vargs = get_args(args); 147 | if (vargs.size() != 1) { 148 | dprintf("Usage: !dump ImageBase (or ImageName)\n"); 149 | return E_FAIL; 150 | } 151 | 152 | const uint64_t imageBase = GetExpression(vargs[0].c_str()); 153 | dprintf("Image Base is %p\n", imageBase); 154 | 155 | const auto iats = GetAllIATs(imageBase, dbgCtl); 156 | if (!iats) { 157 | dprintf("Failed to get IATs\n"); 158 | return E_FAIL; 159 | } 160 | 161 | DumpHybridAuxiliaryIat(iats.value()); 162 | return S_OK; 163 | } 164 | catch (const std::system_error& err) { 165 | ExtensionApis.lpOutputRoutine("Error (%s) occured\n", err.what()); 166 | return E_FAIL; 167 | } 168 | catch (const std::runtime_error& err) { 169 | ExtensionApis.lpOutputRoutine("Error (%s) occured\n", err.what()); 170 | return E_FAIL; 171 | } 172 | } 173 | } 174 | 175 | DECLARE_API(help) { 176 | UNREFERENCED_PARAMETER(args); 177 | UNREFERENCED_PARAMETER(dwProcessor); 178 | UNREFERENCED_PARAMETER(dwCurrentPc); 179 | UNREFERENCED_PARAMETER(hCurrentThread); 180 | UNREFERENCED_PARAMETER(hCurrentProcess); 181 | dprintf( 182 | "!dump - dump the Hybrid Auxiliary IAT of a module\n" 183 | "!show - show the Hybrid Auxiliary IAT entry of a function\n" 184 | "!check - check whether Hybrid Auxiliary IAT hooking is used\n" 185 | ); 186 | } 187 | 188 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/dllmain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include "pch.h" 5 | 6 | BOOL APIENTRY DllMain( 7 | HMODULE hModule, 8 | DWORD ul_reason_for_call, 9 | LPVOID lpReserved 10 | ) { 11 | UNREFERENCED_PARAMETER(hModule); 12 | UNREFERENCED_PARAMETER(lpReserved); 13 | switch (ul_reason_for_call) 14 | { 15 | case DLL_PROCESS_ATTACH: 16 | case DLL_THREAD_ATTACH: 17 | case DLL_THREAD_DETACH: 18 | case DLL_PROCESS_DETACH: 19 | break; 20 | } 21 | return TRUE; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/framework.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #pragma once 5 | 6 | #define WIN32_LEAN_AND_MEAN 7 | 8 | #include 9 | 10 | // Define KDEXT_64BIT to make all wdbgexts APIs recognize 64 bit addresses 11 | // It is recommended for extensions to use 64 bit headers from wdbgexts so 12 | // the extensions could support 64 bit targets. 13 | // 14 | #define KDEXT_64BIT 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "dbg_ctl_wrapper.hpp" 28 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/pch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include "pch.h" 5 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/pch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #ifndef PCH_H 5 | #define PCH_H 6 | 7 | #include "framework.h" 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/pe_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include "pch.h" 5 | 6 | #include "pe_utils.h" 7 | #include "utils.h" 8 | 9 | PIMAGE_LOAD_CONFIG_DIRECTORY GetLoadConfigDirectory( 10 | uint64_t imageBase) { 11 | uint32_t rva = GetImageDataDirectoryEntryRva( 12 | imageBase, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG); 13 | return (PIMAGE_LOAD_CONFIG_DIRECTORY)(rva + imageBase); 14 | } 15 | 16 | PIMAGE_IMPORT_DESCRIPTOR GetImportDescriptor( 17 | uint64_t imageBase) { 18 | uint32_t rva = GetImageDataDirectoryEntryRva( 19 | imageBase, IMAGE_DIRECTORY_ENTRY_IMPORT); 20 | return (PIMAGE_IMPORT_DESCRIPTOR)(rva + imageBase); 21 | } 22 | 23 | uint32_t GetImageDataDirectoryEntryRva( 24 | uint64_t imageBase, 25 | uint32_t dataDirectoryEntryId) { 26 | IMAGE_DOS_HEADER dosHeader {}; 27 | ULONG cb = 0; 28 | ReadMemory(imageBase, &dosHeader, sizeof(IMAGE_DOS_HEADER), &cb); 29 | if (cb != sizeof(IMAGE_DOS_HEADER)) { 30 | dprintf("Cannot read DOS header"); 31 | return 0; 32 | } 33 | 34 | IMAGE_NT_HEADERS ntHeaders {}; 35 | ReadMemory(imageBase + dosHeader.e_lfanew, &ntHeaders, sizeof(IMAGE_NT_HEADERS), &cb); 36 | if (cb != sizeof(IMAGE_NT_HEADERS)) { 37 | dprintf("Cannot read NT header"); 38 | return 0; 39 | } 40 | 41 | return ntHeaders.OptionalHeader.DataDirectory[dataDirectoryEntryId].VirtualAddress; 42 | } 43 | 44 | std::optional GetIatBaseAddress( 45 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc, 46 | ULONGLONG imageBase) { 47 | ULONGLONG baseAddr = 0xffffffffffffffff; 48 | 49 | auto iter = imageImportDesc; 50 | auto name = ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, Name)); 51 | while (name != NULL) { 52 | auto imageThunk = ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, FirstThunk)) + imageBase; 53 | if (imageThunk < baseAddr) { 54 | baseAddr = imageThunk; 55 | } 56 | 57 | iter++; 58 | name = ReadMemberFromStruct(iter, offsetof(IMAGE_IMPORT_DESCRIPTOR, Name)); 59 | } 60 | 61 | if (baseAddr == 0xffffffffffffffff) { 62 | return std::nullopt; 63 | } 64 | 65 | return baseAddr; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/pe_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #pragma once 5 | 6 | #include "pch.h" 7 | 8 | PIMAGE_LOAD_CONFIG_DIRECTORY GetLoadConfigDirectory( 9 | uint64_t imageBase); 10 | 11 | uint32_t GetImageDataDirectoryEntryRva( 12 | uint64_t imageBase, 13 | uint32_t dataDirectoryEntryId); 14 | 15 | PIMAGE_IMPORT_DESCRIPTOR GetImportDescriptor( 16 | uint64_t imageBase); 17 | 18 | std::optional GetIatBaseAddress( 19 | PIMAGE_IMPORT_DESCRIPTOR imageImportDesc, 20 | ULONGLONG imageBase); 21 | 22 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #include "pch.h" 5 | #include "utils.h" 6 | 7 | std::vector get_args(const char *args) { 8 | std::vector string_array; 9 | const char *prev, *p; 10 | prev = p = args; 11 | while (*p) { 12 | if (*p == ' ') { 13 | if (p > prev) 14 | string_array.emplace_back(args, prev - args, p - prev); 15 | prev = p + 1; 16 | } 17 | ++p; 18 | } 19 | if (p > prev) { 20 | string_array.emplace_back(args, prev - args, p - prev); 21 | } 22 | return string_array; 23 | } 24 | 25 | std::string to_hex_string(uint64_t i) { 26 | std::stringstream ss; 27 | ss << std::hex << i; 28 | return ss.str(); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /hybrid_aux_iat/arm64ecext/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) FFRI Security, Inc., 2021 / Author: FFRI Security, Inc. 3 | */ 4 | #pragma once 5 | 6 | #include "pch.h" 7 | 8 | std::vector get_args(const char* args); 9 | std::string to_hex_string(uint64_t i); 10 | 11 | template 12 | T ReadMemberFromStruct(S* structData, 13 | const size_t offset) { 14 | auto readData = (T)0; 15 | DWORD sizeRead = 0; 16 | ReadMemory((ULONG64)structData + offset, 17 | &readData, 18 | sizeof(T), 19 | &sizeRead); 20 | if (sizeRead != sizeof(T)) { 21 | throw std::runtime_error("Cannot read memory at ReadMemberFromStruct"); 22 | } 23 | return readData; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /hybrid_aux_iat/assets/HybridAuxIATHooking.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFRI/ProjectChameleon/4bec0a3464be29f3bd65f6f563813a6955e612d1/hybrid_aux_iat/assets/HybridAuxIATHooking.gif --------------------------------------------------------------------------------