├── LICENSE ├── README.md └── kli.hpp /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kli 2 | 3 | Simple header only, kernel-mode alternative to [lazy_importer](https://github.com/JustasMasiulis/lazy_importer). 4 | 5 | # Example 6 | 7 | ```cpp 8 | // Same as KeBugCheck(XBOX_360_SYSTEM_CRASH); 9 | KLI_FN(KeBugCheck)(XBOX_360_SYSTEM_CRASH); 10 | 11 | // Same as ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'enoN'); 12 | KLI_FN(ExAllocatePoolWithTag)(NonPagedPool, PAGE_SIZE, 'enoN'); 13 | ``` 14 | 15 | # How it works 16 | The macro ``KLI_FN`` hashes the name of desired function in compiletime (using fnv1a64), and in runtime it will enumerate the Export Address Table (EAT) of `ntoskrnl.exe` to compare against this hash. 17 | To get the kernel base, it uses the SIDT instruction to find the ``nt!KiDivideErrorFault`` Interrupt Service Routine (ISR), and abuses the fact that ntoskrnl.exe is mapped using 2MiB pages to walk downwards until 18 | a valid PE image is found. To avoid issues with discardable sections, checks are ran on the PE image to make sure it's ntoskrnl (otherwise you risk finding random drivers). 19 | 20 | # Output 21 | 22 | ```cpp 23 | NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 24 | { 25 | unsigned __int64 i; // rdx 26 | __int64 v3; // rax 27 | __int64 v4; // rax 28 | unsigned __int64 v5; // r9 29 | __int128 v6; // xmm0 30 | __int64 v7; // xmm1_8 31 | char v8; // al 32 | __int128 *v9; // r9 33 | __int64 v10; // rcx 34 | _DWORD *v11; // rcx 35 | unsigned __int64 v12; // r11 36 | unsigned int *v13; // r9 37 | unsigned int v14; // edi 38 | unsigned __int64 v15; // rbx 39 | __int64 v16; // rdx 40 | __int64 v17; // r10 41 | char *v18; // rcx 42 | char v19; // al 43 | void (__fastcall *v21)(__int64, __int64, _QWORD, unsigned int *); // r8 44 | _WORD v22[8]; // [rsp+20h] [rbp-30h] BYREF 45 | __int128 v23; // [rsp+30h] [rbp-20h] BYREF 46 | __int64 v24; // [rsp+40h] [rbp-10h] 47 | int v25; // [rsp+48h] [rbp-8h] 48 | __int16 v26; // [rsp+4Ch] [rbp-4h] 49 | char v27; // [rsp+4Eh] [rbp-2h] 50 | char v28; // [rsp+4Fh] [rbp-1h] 51 | 52 | i = qword_140003000; 53 | if ( !qword_140003000 ) 54 | { 55 | __sidt(v22); 56 | if ( !*(_QWORD *)&v22[1] ) 57 | __debugbreak(); 58 | for ( i = ((*(unsigned __int16 *)(*(_QWORD *)&v22[1] + 6i64) | ((unsigned __int64)*(unsigned int *)(*(_QWORD *)&v22[1] + 8i64) << 16)) & 0xFFFFFFFFFFFFFFE0ui64) << 16; 59 | ; 60 | i -= 0x200000i64 ) 61 | { 62 | if ( *(_WORD *)i == 23117 ) 63 | { 64 | v3 = *(int *)(i + 60); 65 | if ( *(_DWORD *)(v3 + i) == 17744 && *(_WORD *)(v3 + i + 4) == 0x8664 ) 66 | { 67 | v4 = *(unsigned int *)(v3 + i + 136); 68 | v28 = 0; 69 | v5 = i + *(unsigned int *)(v4 + i + 12); 70 | v6 = *(_OWORD *)v5; 71 | v25 = *(_DWORD *)(v5 + 24); 72 | v7 = *(_QWORD *)(v5 + 16); 73 | v26 = *(_WORD *)(v5 + 28); 74 | v27 = *(_BYTE *)(v5 + 30); 75 | v23 = v6; 76 | v24 = v7; 77 | v8 = v6; 78 | v9 = &v23; 79 | v10 = 0xCBF29CE484222325ui64; 80 | if ( (_BYTE)v6 ) 81 | { 82 | do 83 | { 84 | v9 = (__int128 *)((char *)v9 + 1); 85 | v10 = 0x100000001B3i64 * (v8 ^ (unsigned __int64)v10); 86 | v8 = *(_BYTE *)v9; 87 | } 88 | while ( *(_BYTE *)v9 ); 89 | if ( v10 == 0x9BE7F70164F3DBF0ui64 ) 90 | break; 91 | } 92 | } 93 | } 94 | } 95 | qword_140003000 = i; 96 | } 97 | v11 = (_DWORD *)(i + *(unsigned int *)(*(int *)(i + 60) + i + 136)); 98 | v12 = i + (unsigned int)v11[7]; 99 | v13 = (unsigned int *)(i + (unsigned int)v11[8]); 100 | v14 = v11[6]; 101 | v15 = i + (unsigned int)v11[9]; 102 | v16 = 0i64; 103 | if ( v14 ) 104 | { 105 | while ( 1 ) 106 | { 107 | v17 = 0xCBF29CE484222325ui64; 108 | v18 = (char *)(qword_140003000 + *v13); 109 | v19 = *v18; 110 | if ( *v18 ) 111 | { 112 | do 113 | { 114 | ++v18; 115 | v17 = 0x100000001B3i64 * (v19 ^ (unsigned __int64)v17); 116 | v19 = *v18; 117 | } 118 | while ( *v18 ); 119 | if ( v17 == 0xDA68D5AF5F40988Fui64 ) 120 | break; 121 | } 122 | v16 = (unsigned int)(v16 + 1); 123 | ++v13; 124 | if ( (unsigned int)v16 >= v14 ) 125 | goto LABEL_18; 126 | } 127 | v21 = (void (__fastcall *)(__int64, __int64, _QWORD, unsigned int *))(qword_140003000 128 | + *(unsigned int *)(v12 129 | + 4i64 130 | * *(unsigned __int16 *)(v15 + 2i64 * (unsigned int)v16))); 131 | v21(864i64, v16, v21, v13); 132 | } 133 | else 134 | { 135 | LABEL_18: 136 | __debugbreak(); 137 | MEMORY[0](864i64, v16, 0i64, v13); 138 | } 139 | return 0; 140 | } 141 | ``` 142 | 143 | # Credits 144 | - https://twitter.com/JustasMasiulis for making [lazy_importer](https://github.com/JustasMasiulis/lazy_importer) 145 | - https://twitter.com/Ch40zz_ codereview/debugging 146 | - https://twitter.com/duk_37 codereview 147 | -------------------------------------------------------------------------------- /kli.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Adrian Johnsen 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 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | #pragma warning(disable: 4201) 23 | 24 | #ifdef _MSC_VER 25 | #define _KLI_FORCEINLINE __forceinline 26 | #else 27 | #define _KLI_FORCEINLINE __attribute__((always_inline)) 28 | #endif 29 | 30 | #ifndef KLI_DONT_INLINE 31 | #define KLI_FORCEINLINE _KLI_FORCEINLINE 32 | #else 33 | #define KLI_FORCEINLINE inline 34 | #endif 35 | 36 | namespace kli { 37 | // Some people have issues with header. 38 | namespace type_traits 39 | { 40 | template 41 | struct remove_reference { 42 | using type = Type; 43 | }; 44 | 45 | template 46 | struct remove_reference { 47 | using type = Type; 48 | }; 49 | 50 | template 51 | struct remove_reference { 52 | using type = Type; 53 | }; 54 | 55 | template 56 | using remove_reference_t = typename remove_reference::type; 57 | 58 | template 59 | struct remove_const { 60 | using type = Type; 61 | }; 62 | 63 | template 64 | struct remove_const { 65 | using type = Type; 66 | }; 67 | 68 | template 69 | using remove_const_t = typename remove_const::type; 70 | } 71 | 72 | namespace cache { 73 | inline uintptr_t kernel_base; 74 | } 75 | 76 | namespace literals { 77 | KLI_FORCEINLINE constexpr size_t operator ""_KiB(size_t num) { return num << 10; } 78 | KLI_FORCEINLINE constexpr size_t operator ""_MiB(size_t num) { return num << 20; } 79 | KLI_FORCEINLINE constexpr size_t operator ""_GiB(size_t num) { return num << 30; } 80 | KLI_FORCEINLINE constexpr size_t operator ""_TiB(size_t num) { return num << 40; } 81 | } 82 | using namespace literals; 83 | 84 | namespace hash { 85 | namespace detail { 86 | template 87 | struct fnv_constants; 88 | 89 | template <> 90 | struct fnv_constants 91 | { 92 | constexpr static uint32_t default_offset_basis = 0x811C9DC5UL; 93 | constexpr static uint32_t prime = 0x01000193UL; 94 | }; 95 | 96 | template <> 97 | struct fnv_constants 98 | { 99 | constexpr static uint64_t default_offset_basis = 0xCBF29CE484222325ULL; 100 | constexpr static uint64_t prime = 0x100000001B3ULL; 101 | }; 102 | 103 | template 104 | struct char_traits; 105 | 106 | template <> 107 | struct char_traits 108 | { 109 | KLI_FORCEINLINE static constexpr char to_lower(char c) { return c | ' '; }; 110 | KLI_FORCEINLINE static constexpr char to_upper(char c) { return c & '_'; }; // equivalent to c & ~' ' 111 | KLI_FORCEINLINE static constexpr char flip_case(char c) { return c ^ ' '; }; 112 | KLI_FORCEINLINE static constexpr bool is_caps(char c) { return (c & ' ') == ' '; } 113 | }; 114 | 115 | template <> 116 | struct char_traits 117 | { 118 | KLI_FORCEINLINE static constexpr wchar_t to_lower(wchar_t c) { return c | L' '; }; 119 | KLI_FORCEINLINE static constexpr wchar_t to_upper(wchar_t c) { return c & L'_'; }; // equivalent to c & ~' ' 120 | KLI_FORCEINLINE static constexpr wchar_t flip_case(wchar_t c) { return c ^ L' '; }; 121 | KLI_FORCEINLINE static constexpr bool is_caps(wchar_t c) { return (c & L' ') == L' '; } 122 | }; 123 | } 124 | 125 | // Shortcuts for character traits 126 | template KLI_FORCEINLINE constexpr Char to_lower(Char c) { return detail::char_traits::to_lower(c); } 127 | template KLI_FORCEINLINE constexpr Char to_upper(Char c) { return detail::char_traits::to_upper(c); } 128 | template KLI_FORCEINLINE constexpr Char flip_case(Char c) { return detail::char_traits::flip_case(c); } 129 | 130 | template 131 | KLI_FORCEINLINE constexpr Type hash_fnv1a(const Char *str) 132 | { 133 | Type val = detail::fnv_constants::default_offset_basis; 134 | 135 | for (; *str != static_cast(0); ++str) { 136 | Char c = *str; 137 | 138 | if constexpr (ToLower) 139 | c = to_lower(c); 140 | 141 | val ^= static_cast(c); 142 | val *= static_cast(detail::fnv_constants::prime); 143 | } 144 | 145 | return val; 146 | } 147 | 148 | // 149 | // Dumb hack to force a constexpr value to be evaluated in compiletime 150 | // 151 | 152 | template 153 | struct force_cx 154 | { 155 | constexpr static auto value = Value; 156 | }; 157 | 158 | #define _KLI_HASH_RTS(str) (::kli::hash::hash_fnv1a>, false>((str))) 159 | #define _KLI_HASH_RTS_TOLOWER(str) (::kli::hash::hash_fnv1a>, true>((str))) 160 | 161 | #define _KLI_HASH_STR(str) (::kli::hash::force_cx>, false>((str))>::value) 162 | #define _KLI_HASH_STR_TOLOWER(str) (::kli::hash::force_cx>, true>((str))>::value) 163 | 164 | #ifndef KLI_USE_TOLOWER 165 | // Don't use tolower 166 | #define KLI_HASH_RTS(str) _KLI_HASH_RTS(str) 167 | #define KLI_HASH_STR(str) _KLI_HASH_STR(str) 168 | #else 169 | // Use tolower 170 | #define KLI_HASH_RTS(str) _KLI_HASH_RTS_TOLOWER(str) 171 | #define KLI_HASH_STR(str) _KLI_HASH_STR_TOLOWER(str) 172 | #endif 173 | } 174 | 175 | namespace detail { 176 | #pragma pack(push, 1) 177 | enum exception_vector 178 | { 179 | VECTOR_DIVIDE_ERROR_EXCEPTION = 0, 180 | VECTOR_DEBUG_EXCEPTION = 1, 181 | VECTOR_NMI_INTERRUPT = 2, 182 | VECTOR_BREAKPOINT_EXCEPTION = 3, 183 | VECTOR_OVERFLOW_EXCEPTION = 4, 184 | VECTOR_BOUND_EXCEPTION = 5, 185 | VECTOR_UNDEFINED_OPCODE_EXCEPTION = 6, 186 | VECTOR_DEVICE_NOT_AVAILABLE_EXCEPTION = 7, 187 | VECTOR_DOUBLE_FAULT_EXCEPTION = 8, 188 | VECTOR_COPROCESSOR_SEGMENT_OVERRUN = 9, 189 | VECTOR_INVALID_TSS_EXCEPTION = 10, 190 | VECTOR_SEGMENT_NOT_PRESENT = 11, 191 | VECTOR_STACK_FAULT_EXCEPTION = 12, 192 | VECTOR_GENERAL_PROTECTION_EXCEPTION = 13, 193 | VECTOR_PAGE_FAULT_EXCEPTION = 14, 194 | VECTOR_X87_FLOATING_POINT_ERROR = 16, 195 | VECTOR_ALIGNMENT_CHECK_EXCEPTION = 17, 196 | VECTOR_MACHINE_CHECK_EXCEPTION = 18, 197 | VECTOR_SIMD_FLOATING_POINT_EXCEPTION = 19, 198 | VECTOR_VIRTUALIZATION_EXCEPTION = 20, 199 | VECTOR_SECURITY_EXCEPTION = 30 200 | }; 201 | 202 | union idt_entry 203 | { 204 | struct 205 | { 206 | uint64_t low64; 207 | uint64_t high64; 208 | } split; 209 | 210 | struct 211 | { 212 | uint16_t offset_low; 213 | 214 | union 215 | { 216 | uint16_t flags; 217 | 218 | struct 219 | { 220 | uint16_t rpl : 2; 221 | uint16_t table : 1; 222 | uint16_t index : 13; 223 | }; 224 | } segment_selector; 225 | uint8_t reserved0; 226 | union 227 | { 228 | uint8_t flags; 229 | 230 | struct 231 | { 232 | uint8_t gate_type : 4; 233 | uint8_t storage_segment : 1; 234 | uint8_t dpl : 2; 235 | uint8_t present : 1; 236 | }; 237 | } type_attr; 238 | 239 | uint16_t offset_mid; 240 | uint32_t offset_high; 241 | uint32_t reserved1; 242 | }; 243 | }; 244 | 245 | struct idtr 246 | { 247 | uint16_t idt_limit; 248 | uint64_t idt_base; 249 | 250 | KLI_FORCEINLINE idt_entry *operator [](size_t index) { 251 | return &((idt_entry *)idt_base)[index]; 252 | } 253 | }; 254 | #pragma pack(pop) 255 | 256 | typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header 257 | uint16_t e_magic; // Magic number 258 | uint16_t e_cblp; // Bytes on last page of file 259 | uint16_t e_cp; // Pages in file 260 | uint16_t e_crlc; // Relocations 261 | uint16_t e_cparhdr; // GetSize of header in paragraphs 262 | uint16_t e_minalloc; // Minimum extra paragraphs needed 263 | uint16_t e_maxalloc; // Maximum extra paragraphs needed 264 | uint16_t e_ss; // Initial (relative) SS value 265 | uint16_t e_sp; // Initial SP value 266 | uint16_t e_csum; // Checksum 267 | uint16_t e_ip; // Initial IP value 268 | uint16_t e_cs; // Initial (relative) CS value 269 | uint16_t e_lfarlc; // File address of relocation table 270 | uint16_t e_ovno; // Overlay number 271 | uint16_t e_res[4]; // Reserved words 272 | uint16_t e_oemid; // OEM identifier (for e_oeminfo) 273 | uint16_t e_oeminfo; // OEM information; e_oemid specific 274 | uint16_t e_res2[10]; // Reserved words 275 | int32_t e_lfanew; // File address of new exe header 276 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 277 | 278 | typedef struct _IMAGE_FILE_HEADER { 279 | uint16_t Machine; 280 | uint16_t NumberOfSections; 281 | uint32_t TimeDateStamp; 282 | uint32_t PointerToSymbolTable; 283 | uint32_t NumberOfSymbols; 284 | uint16_t SizeOfOptionalHeader; 285 | uint16_t Characteristics; 286 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 287 | 288 | typedef struct _IMAGE_DATA_DIRECTORY { 289 | uint32_t VirtualAddress; 290 | uint32_t Size; 291 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 292 | 293 | typedef struct _IMAGE_OPTIONAL_HEADER64 { 294 | uint16_t Magic; 295 | uint8_t MajorLinkerVersion; 296 | uint8_t MinorLinkerVersion; 297 | uint32_t SizeOfCode; 298 | uint32_t SizeOfInitializedData; 299 | uint32_t SizeOfUninitializedData; 300 | uint32_t AddressOfEntryPoint; 301 | uint32_t BaseOfCode; 302 | uint64_t ImageBase; 303 | uint32_t SectionAlignment; 304 | uint32_t FileAlignment; 305 | uint16_t MajorOperatingSystemVersion; 306 | uint16_t MinorOperatingSystemVersion; 307 | uint16_t MajorImageVersion; 308 | uint16_t MinorImageVersion; 309 | uint16_t MajorSubsystemVersion; 310 | uint16_t MinorSubsystemVersion; 311 | uint32_t Win32VersionValue; 312 | uint32_t SizeOfImage; 313 | uint32_t SizeOfHeaders; 314 | uint32_t CheckSum; 315 | uint16_t Subsystem; 316 | uint16_t DllCharacteristics; 317 | uint64_t SizeOfStackReserve; 318 | uint64_t SizeOfStackCommit; 319 | uint64_t SizeOfHeapReserve; 320 | uint64_t SizeOfHeapCommit; 321 | uint32_t LoaderFlags; 322 | uint32_t NumberOfRvaAndSizes; 323 | IMAGE_DATA_DIRECTORY DataDirectory[16]; 324 | } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; 325 | 326 | typedef struct _IMAGE_NT_HEADERS64 { 327 | uint32_t Signature; 328 | IMAGE_FILE_HEADER FileHeader; 329 | IMAGE_OPTIONAL_HEADER64 OptionalHeader; 330 | } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; 331 | 332 | typedef struct _IMAGE_EXPORT_DIRECTORY { 333 | uint32_t Characteristics; 334 | uint32_t TimeDateStamp; 335 | uint16_t MajorVersion; 336 | uint16_t MinorVersion; 337 | uint32_t Name; 338 | uint32_t Base; 339 | uint32_t NumberOfFunctions; 340 | uint32_t NumberOfNames; 341 | uint32_t AddressOfFunctions; // RVA from base of image 342 | uint32_t AddressOfNames; // RVA from base of image 343 | uint32_t AddressOfNameOrdinals; // RVA from base of image 344 | } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; 345 | 346 | constexpr uint16_t IMAGE_DOS_SIGNATURE = 0x5A4D; 347 | constexpr uint32_t IMAGE_NT_SIGNATURE = 0x00004550; 348 | constexpr uint16_t IMAGE_FILE_MACHINE_AMD64 = 0x8664; 349 | constexpr auto IMAGE_DIRECTORY_ENTRY_EXPORT = 0; 350 | 351 | KLI_FORCEINLINE bool is_kernel_base(uintptr_t addr) 352 | { 353 | const auto dos_header = (PIMAGE_DOS_HEADER)addr; 354 | 355 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 356 | return false; 357 | 358 | const auto nt_headers = (PIMAGE_NT_HEADERS64)(addr + dos_header->e_lfanew); 359 | 360 | if (nt_headers->Signature != IMAGE_NT_SIGNATURE) 361 | return false; 362 | 363 | if (nt_headers->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) 364 | return false; 365 | 366 | // 367 | // Check the dll name in EAT->Name 368 | // 369 | const auto export_directory = (PIMAGE_EXPORT_DIRECTORY)(addr + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 370 | const auto dll_name = (const char *)(addr + export_directory->Name); 371 | const auto dll_name_hash = KLI_HASH_RTS(dll_name); 372 | 373 | if (dll_name_hash != KLI_HASH_STR("ntoskrnl.exe")) 374 | return false; 375 | 376 | return true; 377 | } 378 | 379 | KLI_FORCEINLINE uintptr_t find_kernel_base() 380 | { 381 | idtr k_idtr; 382 | __sidt((void *)&k_idtr); 383 | 384 | if (!k_idtr.idt_base) 385 | __debugbreak(); 386 | 387 | // 388 | // Find KiDivideErrorFault through IDT (index 0) 389 | // 390 | const auto isr_divide_error = k_idtr[VECTOR_DIVIDE_ERROR_EXCEPTION]; 391 | const auto pfn_KiDivideErrorFault = ((uintptr_t)isr_divide_error->offset_low) | 392 | (((uintptr_t)isr_divide_error->offset_mid) << 16) | 393 | (((uintptr_t)isr_divide_error->offset_high) << 32); 394 | 395 | // 396 | // Walk down from KiDivideErrorFault for 'MZ' word. Because of discardable sections we might run into a random PE image, 397 | // so is_kernel_base checks DLL name in EAT to make sure we caught ntoskrnl.exe. We walk down 2 MiB because ntoskrnl.exe is mapped 398 | // using PDEs and not PTEs, so the base will always be 2 MiB aligned. 399 | // 400 | const auto aligned_isr = pfn_KiDivideErrorFault & ~(2_MiB - 1); 401 | uintptr_t address = aligned_isr; 402 | 403 | while (!is_kernel_base(address)) { 404 | address -= 2_MiB; 405 | } 406 | 407 | return address; 408 | } 409 | } 410 | 411 | template 412 | KLI_FORCEINLINE uintptr_t find_kernel_export() 413 | { 414 | if (!cache::kernel_base) 415 | cache::kernel_base = detail::find_kernel_base(); 416 | 417 | const auto dos_header = (detail::PIMAGE_DOS_HEADER)cache::kernel_base; 418 | const auto nt_headers = (detail::PIMAGE_NT_HEADERS64)(cache::kernel_base + dos_header->e_lfanew); 419 | const auto export_directory = (detail::PIMAGE_EXPORT_DIRECTORY)(cache::kernel_base + 420 | nt_headers->OptionalHeader.DataDirectory[detail::IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 421 | 422 | const auto address_of_functions = (uint32_t *)(cache::kernel_base + export_directory->AddressOfFunctions); 423 | const auto address_of_names = (uint32_t *)(cache::kernel_base + export_directory->AddressOfNames); 424 | const auto address_of_name_ordinals = (uint16_t *)(cache::kernel_base + export_directory->AddressOfNameOrdinals); 425 | 426 | for (uint32_t i = 0; i < export_directory->NumberOfNames; ++i) 427 | { 428 | const auto export_entry_name = (char *)(cache::kernel_base + address_of_names[i]); 429 | const auto export_entry_hash = KLI_HASH_RTS(export_entry_name); 430 | 431 | // 432 | // address_of_functions is indexed through an ordinal 433 | // address_of_name_ordinals gets the ordinal through our own index - i. 434 | // 435 | if (export_entry_hash == ExportHash) 436 | return cache::kernel_base + address_of_functions[address_of_name_ordinals[i]]; 437 | } 438 | 439 | __debugbreak(); 440 | return { }; 441 | } 442 | 443 | template 444 | KLI_FORCEINLINE uintptr_t find_kernel_export_cached() 445 | { 446 | static uintptr_t address = 0; 447 | if (!address) 448 | address = find_kernel_export(); 449 | 450 | return address; 451 | } 452 | } 453 | 454 | #ifdef KLI_DISABLE_CACHE 455 | #define KLI_FN(name) ((decltype(&##name))(::kli::find_kernel_export())) 456 | #else 457 | #define KLI_FN(name) ((decltype(&##name))(::kli::find_kernel_export_cached())) 458 | #endif 459 | --------------------------------------------------------------------------------