├── .editorconfig
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .gitmodules
├── .idea
├── .gitignore
├── Lyptus.iml
├── cmake.xml
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── CMakeLists.txt
├── LICENSE.txt
├── README.md
├── build.ps1
├── res
└── Lyptus.json
├── src
├── lyptus
│ ├── lyptus.cpp
│ └── lyptus.hpp
├── main.cpp
├── patcher
│ ├── patcher.cpp
│ └── patcher.hpp
└── pch.hpp
└── vcpkg.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = crlf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | max_line_length = 120
10 | tab_width = 4
11 | ij_continuation_indent_size = 8
12 | ij_formatter_off_tag = @formatter:off
13 | ij_formatter_on_tag = @formatter:on
14 | ij_formatter_tags_enabled = false
15 | ij_smart_tabs = false
16 | ij_visual_guides = none
17 | ij_wrap_on_typing = false
18 |
19 | [.editorconfig]
20 | ij_editorconfig_align_group_field_declarations = false
21 | ij_editorconfig_space_after_colon = false
22 | ij_editorconfig_space_after_comma = true
23 | ij_editorconfig_space_before_colon = false
24 | ij_editorconfig_space_before_comma = false
25 | ij_editorconfig_spaces_around_assignment_operators = true
26 |
27 | [{*.c,*.c++,*.cc,*.cp,*.cpp,*.cu,*.cuh,*.cxx,*.h,*.h++,*.hh,*.hp,*.hpp,*.hxx,*.i,*.icc,*.ii,*.inl,*.ino,*.ipp,*.m,*.mm,*.pch,*.tcc,*.tpp,version.gen.rc}]
28 | max_line_length = 100
29 | ij_c_add_brief_tag = false
30 | ij_c_add_getter_prefix = true
31 | ij_c_add_setter_prefix = true
32 | ij_c_align_dictionary_pair_values = false
33 | ij_c_align_group_field_declarations = false
34 | ij_c_align_init_list_in_columns = true
35 | ij_c_align_multiline_array_initializer_expression = true
36 | ij_c_align_multiline_assignment = true
37 | ij_c_align_multiline_binary_operation = true
38 | ij_c_align_multiline_chained_methods = false
39 | ij_c_align_multiline_for = true
40 | ij_c_align_multiline_ternary_operation = false
41 | ij_c_array_initializer_comma_on_next_line = false
42 | ij_c_array_initializer_new_line_after_left_brace = false
43 | ij_c_array_initializer_right_brace_on_new_line = false
44 | ij_c_array_initializer_wrap = normal
45 | ij_c_assignment_wrap = off
46 | ij_c_binary_operation_sign_on_next_line = false
47 | ij_c_binary_operation_wrap = normal
48 | ij_c_blank_lines_after_class_header = 0
49 | ij_c_blank_lines_after_imports = 1
50 | ij_c_blank_lines_around_class = 1
51 | ij_c_blank_lines_around_field = 0
52 | ij_c_blank_lines_around_field_in_interface = 0
53 | ij_c_blank_lines_around_method = 1
54 | ij_c_blank_lines_around_method_in_interface = 1
55 | ij_c_blank_lines_around_namespace = 0
56 | ij_c_blank_lines_around_properties_in_declaration = 0
57 | ij_c_blank_lines_around_properties_in_interface = 0
58 | ij_c_blank_lines_before_imports = 1
59 | ij_c_blank_lines_before_method_body = 0
60 | ij_c_block_brace_placement = end_of_line
61 | ij_c_block_brace_style = end_of_line
62 | ij_c_block_comment_at_first_column = true
63 | ij_c_catch_on_new_line = false
64 | ij_c_class_brace_style = end_of_line
65 | ij_c_class_constructor_init_list_align_multiline = true
66 | ij_c_class_constructor_init_list_comma_on_next_line = false
67 | ij_c_class_constructor_init_list_new_line_after_colon = never
68 | ij_c_class_constructor_init_list_new_line_before_colon = if_long
69 | ij_c_class_constructor_init_list_wrap = normal
70 | ij_c_copy_is_deep = false
71 | ij_c_create_interface_for_categories = true
72 | ij_c_declare_generated_methods = true
73 | ij_c_description_include_member_names = true
74 | ij_c_discharged_short_ternary_operator = false
75 | ij_c_do_not_add_breaks = false
76 | ij_c_do_while_brace_force = never
77 | ij_c_else_on_new_line = false
78 | ij_c_enum_constants_comma_on_next_line = false
79 | ij_c_enum_constants_wrap = on_every_item
80 | ij_c_for_brace_force = never
81 | ij_c_for_statement_new_line_after_left_paren = false
82 | ij_c_for_statement_right_paren_on_new_line = false
83 | ij_c_for_statement_wrap = off
84 | ij_c_function_brace_placement = end_of_line
85 | ij_c_function_call_arguments_align_multiline = false
86 | ij_c_function_call_arguments_align_multiline_pars = false
87 | ij_c_function_call_arguments_comma_on_next_line = false
88 | ij_c_function_call_arguments_new_line_after_lpar = false
89 | ij_c_function_call_arguments_new_line_before_rpar = false
90 | ij_c_function_call_arguments_wrap = normal
91 | ij_c_function_non_top_after_return_type_wrap = normal
92 | ij_c_function_parameters_align_multiline = true
93 | ij_c_function_parameters_align_multiline_pars = false
94 | ij_c_function_parameters_comma_on_next_line = false
95 | ij_c_function_parameters_new_line_after_lpar = true
96 | ij_c_function_parameters_new_line_before_rpar = true
97 | ij_c_function_parameters_wrap = normal
98 | ij_c_function_top_after_return_type_wrap = normal
99 | ij_c_generate_additional_eq_operators = true
100 | ij_c_generate_additional_rel_operators = true
101 | ij_c_generate_class_constructor = true
102 | ij_c_generate_comparison_operators_use_std_tie = false
103 | ij_c_generate_instance_variables_for_properties = ask
104 | ij_c_generate_operators_as_members = true
105 | ij_c_header_guard_style_pattern = ${PROJECT_NAME}_${FILE_NAME}_${EXT}
106 | ij_c_if_brace_force = never
107 | ij_c_in_line_short_ternary_operator = true
108 | ij_c_indent_block_comment = true
109 | ij_c_indent_c_struct_members = 4
110 | ij_c_indent_case_from_switch = true
111 | ij_c_indent_class_members = 4
112 | ij_c_indent_directive_as_code = false
113 | ij_c_indent_implementation_members = 0
114 | ij_c_indent_inside_code_block = 4
115 | ij_c_indent_interface_members = 0
116 | ij_c_indent_interface_members_except_ivars_block = false
117 | ij_c_indent_namespace_members = 4
118 | ij_c_indent_preprocessor_directive = 0
119 | ij_c_indent_visibility_keywords = 0
120 | ij_c_insert_override = true
121 | ij_c_insert_virtual_with_override = false
122 | ij_c_introduce_auto_vars = false
123 | ij_c_introduce_const_params = false
124 | ij_c_introduce_const_vars = false
125 | ij_c_introduce_generate_property = false
126 | ij_c_introduce_generate_synthesize = true
127 | ij_c_introduce_globals_to_header = true
128 | ij_c_introduce_prop_to_private_category = false
129 | ij_c_introduce_static_consts = true
130 | ij_c_introduce_use_ns_types = false
131 | ij_c_ivars_prefix = _
132 | ij_c_keep_blank_lines_before_end = 2
133 | ij_c_keep_blank_lines_before_right_brace = 2
134 | ij_c_keep_blank_lines_in_code = 2
135 | ij_c_keep_blank_lines_in_declarations = 2
136 | ij_c_keep_case_expressions_in_one_line = false
137 | ij_c_keep_control_statement_in_one_line = true
138 | ij_c_keep_directive_at_first_column = true
139 | ij_c_keep_first_column_comment = true
140 | ij_c_keep_line_breaks = true
141 | ij_c_keep_nested_namespaces_in_one_line = false
142 | ij_c_keep_simple_blocks_in_one_line = true
143 | ij_c_keep_simple_methods_in_one_line = true
144 | ij_c_keep_structures_in_one_line = true
145 | ij_c_lambda_capture_list_align_multiline = false
146 | ij_c_lambda_capture_list_align_multiline_bracket = false
147 | ij_c_lambda_capture_list_comma_on_next_line = false
148 | ij_c_lambda_capture_list_new_line_after_lbracket = false
149 | ij_c_lambda_capture_list_new_line_before_rbracket = false
150 | ij_c_lambda_capture_list_wrap = off
151 | ij_c_line_comment_add_space = false
152 | ij_c_line_comment_at_first_column = true
153 | ij_c_method_brace_placement = end_of_line
154 | ij_c_method_call_arguments_align_by_colons = true
155 | ij_c_method_call_arguments_align_multiline = false
156 | ij_c_method_call_arguments_special_dictionary_pairs_treatment = true
157 | ij_c_method_call_arguments_wrap = off
158 | ij_c_method_call_chain_wrap = off
159 | ij_c_method_parameters_align_by_colons = true
160 | ij_c_method_parameters_align_multiline = false
161 | ij_c_method_parameters_wrap = off
162 | ij_c_namespace_brace_placement = end_of_line
163 | ij_c_parentheses_expression_new_line_after_left_paren = false
164 | ij_c_parentheses_expression_right_paren_on_new_line = false
165 | ij_c_place_assignment_sign_on_next_line = false
166 | ij_c_property_nonatomic = true
167 | ij_c_put_ivars_to_implementation = true
168 | ij_c_refactor_compatibility_aliases_and_classes = true
169 | ij_c_refactor_properties_and_ivars = true
170 | ij_c_release_style = ivar
171 | ij_c_retain_object_parameters_in_constructor = true
172 | ij_c_semicolon_after_method_signature = false
173 | ij_c_shift_operation_align_multiline = true
174 | ij_c_shift_operation_wrap = normal
175 | ij_c_show_non_virtual_functions = false
176 | ij_c_space_after_colon = true
177 | ij_c_space_after_colon_in_foreach = true
178 | ij_c_space_after_colon_in_selector = false
179 | ij_c_space_after_comma = true
180 | ij_c_space_after_cup_in_blocks = false
181 | ij_c_space_after_dictionary_literal_colon = true
182 | ij_c_space_after_for_semicolon = true
183 | ij_c_space_after_init_list_colon = true
184 | ij_c_space_after_method_parameter_type_parentheses = false
185 | ij_c_space_after_method_return_type_parentheses = false
186 | ij_c_space_after_pointer_in_declaration = true
187 | ij_c_space_after_quest = true
188 | ij_c_space_after_reference_in_declaration = true
189 | ij_c_space_after_reference_in_rvalue = false
190 | ij_c_space_after_structures_rbrace = true
191 | ij_c_space_after_superclass_colon = true
192 | ij_c_space_after_type_cast = true
193 | ij_c_space_after_visibility_sign_in_method_declaration = true
194 | ij_c_space_before_autorelease_pool_lbrace = true
195 | ij_c_space_before_catch_keyword = true
196 | ij_c_space_before_catch_left_brace = true
197 | ij_c_space_before_catch_parentheses = true
198 | ij_c_space_before_category_parentheses = true
199 | ij_c_space_before_chained_send_message = true
200 | ij_c_space_before_class_left_brace = true
201 | ij_c_space_before_colon = true
202 | ij_c_space_before_colon_in_foreach = false
203 | ij_c_space_before_comma = false
204 | ij_c_space_before_dictionary_literal_colon = false
205 | ij_c_space_before_do_left_brace = true
206 | ij_c_space_before_else_keyword = true
207 | ij_c_space_before_else_left_brace = true
208 | ij_c_space_before_for_left_brace = true
209 | ij_c_space_before_for_parentheses = true
210 | ij_c_space_before_for_semicolon = false
211 | ij_c_space_before_if_left_brace = true
212 | ij_c_space_before_if_parentheses = true
213 | ij_c_space_before_init_list = false
214 | ij_c_space_before_init_list_colon = true
215 | ij_c_space_before_method_call_parentheses = false
216 | ij_c_space_before_method_left_brace = true
217 | ij_c_space_before_method_parentheses = false
218 | ij_c_space_before_namespace_lbrace = true
219 | ij_c_space_before_pointer_in_declaration = false
220 | ij_c_space_before_property_attributes_parentheses = false
221 | ij_c_space_before_protocols_brackets = true
222 | ij_c_space_before_quest = true
223 | ij_c_space_before_reference_in_declaration = false
224 | ij_c_space_before_superclass_colon = true
225 | ij_c_space_before_switch_left_brace = true
226 | ij_c_space_before_switch_parentheses = true
227 | ij_c_space_before_template_call_lt = false
228 | ij_c_space_before_template_declaration_lt = false
229 | ij_c_space_before_try_left_brace = true
230 | ij_c_space_before_while_keyword = true
231 | ij_c_space_before_while_left_brace = true
232 | ij_c_space_before_while_parentheses = true
233 | ij_c_space_between_adjacent_brackets = false
234 | ij_c_space_between_operator_and_punctuator = false
235 | ij_c_space_within_empty_array_initializer_braces = false
236 | ij_c_spaces_around_additive_operators = true
237 | ij_c_spaces_around_assignment_operators = true
238 | ij_c_spaces_around_bitwise_operators = true
239 | ij_c_spaces_around_equality_operators = true
240 | ij_c_spaces_around_lambda_arrow = true
241 | ij_c_spaces_around_logical_operators = true
242 | ij_c_spaces_around_multiplicative_operators = true
243 | ij_c_spaces_around_pm_operators = false
244 | ij_c_spaces_around_relational_operators = true
245 | ij_c_spaces_around_shift_operators = true
246 | ij_c_spaces_around_unary_operator = false
247 | ij_c_spaces_within_array_initializer_braces = true
248 | ij_c_spaces_within_braces = true
249 | ij_c_spaces_within_brackets = false
250 | ij_c_spaces_within_cast_parentheses = false
251 | ij_c_spaces_within_catch_parentheses = false
252 | ij_c_spaces_within_category_parentheses = false
253 | ij_c_spaces_within_empty_braces = false
254 | ij_c_spaces_within_empty_function_call_parentheses = false
255 | ij_c_spaces_within_empty_function_declaration_parentheses = false
256 | ij_c_spaces_within_empty_lambda_capture_list_bracket = false
257 | ij_c_spaces_within_empty_template_call_ltgt = false
258 | ij_c_spaces_within_empty_template_declaration_ltgt = false
259 | ij_c_spaces_within_for_parentheses = false
260 | ij_c_spaces_within_function_call_parentheses = false
261 | ij_c_spaces_within_function_declaration_parentheses = false
262 | ij_c_spaces_within_if_parentheses = false
263 | ij_c_spaces_within_lambda_capture_list_bracket = false
264 | ij_c_spaces_within_method_parameter_type_parentheses = false
265 | ij_c_spaces_within_method_return_type_parentheses = false
266 | ij_c_spaces_within_parentheses = false
267 | ij_c_spaces_within_property_attributes_parentheses = false
268 | ij_c_spaces_within_protocols_brackets = false
269 | ij_c_spaces_within_send_message_brackets = false
270 | ij_c_spaces_within_switch_parentheses = false
271 | ij_c_spaces_within_template_call_ltgt = false
272 | ij_c_spaces_within_template_declaration_ltgt = false
273 | ij_c_spaces_within_template_double_gt = true
274 | ij_c_spaces_within_while_parentheses = false
275 | ij_c_special_else_if_treatment = true
276 | ij_c_superclass_list_after_colon = never
277 | ij_c_superclass_list_align_multiline = true
278 | ij_c_superclass_list_before_colon = if_long
279 | ij_c_superclass_list_comma_on_next_line = false
280 | ij_c_superclass_list_wrap = on_every_item
281 | ij_c_tag_prefix_of_block_comment = at
282 | ij_c_tag_prefix_of_line_comment = back_slash
283 | ij_c_template_call_arguments_align_multiline = false
284 | ij_c_template_call_arguments_align_multiline_pars = false
285 | ij_c_template_call_arguments_comma_on_next_line = false
286 | ij_c_template_call_arguments_new_line_after_lt = false
287 | ij_c_template_call_arguments_new_line_before_gt = false
288 | ij_c_template_call_arguments_wrap = off
289 | ij_c_template_declaration_function_body_indent = false
290 | ij_c_template_declaration_function_wrap = split_into_lines
291 | ij_c_template_declaration_struct_body_indent = false
292 | ij_c_template_declaration_struct_wrap = split_into_lines
293 | ij_c_template_parameters_align_multiline = false
294 | ij_c_template_parameters_align_multiline_pars = false
295 | ij_c_template_parameters_comma_on_next_line = false
296 | ij_c_template_parameters_new_line_after_lt = false
297 | ij_c_template_parameters_new_line_before_gt = false
298 | ij_c_template_parameters_wrap = off
299 | ij_c_ternary_operation_signs_on_next_line = true
300 | ij_c_ternary_operation_wrap = normal
301 | ij_c_type_qualifiers_placement = before
302 | ij_c_use_modern_casts = true
303 | ij_c_use_setters_in_constructor = true
304 | ij_c_while_brace_force = never
305 | ij_c_while_on_new_line = false
306 | ij_c_wrap_property_declaration = off
307 |
308 | [{*.cmake,CMakeLists.txt}]
309 | ij_cmake_align_multiline_parameters_in_calls = false
310 | ij_cmake_force_commands_case = 2
311 | ij_cmake_keep_blank_lines_in_code = 2
312 | ij_cmake_space_before_for_parentheses = true
313 | ij_cmake_space_before_if_parentheses = true
314 | ij_cmake_space_before_method_call_parentheses = false
315 | ij_cmake_space_before_method_parentheses = false
316 | ij_cmake_space_before_while_parentheses = true
317 | ij_cmake_spaces_within_for_parentheses = false
318 | ij_cmake_spaces_within_if_parentheses = false
319 | ij_cmake_spaces_within_method_call_parentheses = false
320 | ij_cmake_spaces_within_method_parentheses = false
321 | ij_cmake_spaces_within_while_parentheses = false
322 |
323 | [{*.har,*.json,*.jsonc}]
324 | indent_size = 2
325 | ij_json_keep_blank_lines_in_code = 1
326 | ij_json_keep_indents_on_empty_lines = false
327 | ij_json_keep_line_breaks = true
328 | ij_json_space_after_colon = true
329 | ij_json_space_after_comma = true
330 | ij_json_space_before_colon = true
331 | ij_json_space_before_comma = false
332 | ij_json_spaces_within_braces = false
333 | ij_json_spaces_within_brackets = false
334 | ij_json_wrap_long_lines = false
335 |
336 | [{*.apinotes,*.yaml,*.yml,.clang-format,.clang-tidy,_clang-format}]
337 | indent_size = 2
338 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Continuous Integration
2 | on: push
3 |
4 | jobs:
5 | ci:
6 | name: CI
7 | uses: acidicoala/KoalaBox/.github/workflows/build-and-package.yml@9425143c4f36d7296c2ce3318a56fb91e2d576f9
8 | permissions:
9 | contents: write
10 | with:
11 | modules: >-
12 | ["Lyptus"]
13 |
14 | zip_command: >
15 | zip -j $ZIP_NAME
16 | artifacts/*/*.dll
17 | res/Lyptus.json
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "KoalaBox"]
2 | path = KoalaBox
3 | url = https://github.com/acidicoala/KoalaBox.git
4 | [submodule "vcpkg"]
5 | path = vcpkg
6 | url = https://github.com/microsoft/vcpkg.git
7 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/Lyptus.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/cmake.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
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 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.21)
2 |
3 | include(KoalaBox/KoalaBox.cmake)
4 |
5 | configure_globals(KoalaBox)
6 |
7 | project(Lyptus VERSION 1.1.0)
8 |
9 | configure_version_resource("https://github.com/acidicoala/Lyptus")
10 |
11 | configure_build_config()
12 |
13 | configure_library(
14 | SHARED
15 |
16 | ${SRC_DIR}/lyptus/lyptus.cpp
17 | ${SRC_DIR}/patcher/patcher.cpp
18 | ${SRC_DIR}/main.cpp
19 |
20 | ${KOALABOX_SRC_DIR}/koalabox/file_logger/file_logger.cpp
21 | ${KOALABOX_SRC_DIR}/koalabox/loader/loader.cpp
22 | ${KOALABOX_SRC_DIR}/koalabox/win_util/win_util.cpp
23 | ${KOALABOX_SRC_DIR}/koalabox/util/util.cpp
24 | )
25 |
26 | configure_precompile_headers(${CMAKE_PROJECT_NAME} ${SRC_DIR}/pch.hpp)
27 |
28 | set_32_and_64(OUTPUT_NAME Lyptus32 Lyptus64)
29 | configure_output_name(${OUTPUT_NAME})
30 |
31 | configure_include_directories()
32 |
33 | configure_dependencies(${CMAKE_PROJECT_NAME} nlohmann_json spdlog)
34 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | BSD Zero Clause License
2 |
3 | Copyright (c) 2022 by acidicoala
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 | PERFORMANCE OF THIS SOFTWARE.
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🐨 Lyptus 🎋
2 |
3 | A configurable in-memory binary patcher.
4 |
5 | ## 🚀 Usage
6 |
7 | Set up the Lyptus config with a list of patches to apply, and inject the Lyptus DLL into the target process. Consider using [Koaloader] for automatic injection on process start-up.
8 |
9 | [Koaloader]: https://github.com/acidicoala/Koaloader
10 |
11 | [Official forum topic](https://cs.rin.ru/forum/viewtopic.php?p=2536753#p2536753)
12 |
13 | ## ⚙ Configuration
14 |
15 | Lyptus comes with a configuration file `Lyptus.json`, which defines patches that will be applied as soon as Lyptus gets injected into the process. The config file
16 | conforms to the standard JSON format. The description of each available option is presented below:
17 |
18 | * `logging`: Enables or disables logging into a `Koaloader.log` file. Possible values: `true`, `false` (default).
19 | * `patches`: An array of objects that describe patches that will be applied in the order they were defined. Each object has the following properties:
20 | * `name`: A string that informally describes the patch.
21 | * `pattern`: A hexadecimal string that specifies the pattern Lyptus will use when searching. The string can contain only hex symbols [0-9][A-F][a-f], whitespaces [ ], and wildcards [?]. Keep in mind that 2 hex symbols constitute 1 byte, hence the string must have an even number of characters.
22 | * `offset`: A byte offset that will be added to the found address when applying the patch.
23 | * `replacement`: A hexadecimal string that specifies a sequence of bytes to be written at the target address. The string can contain only hex symbols [0-9][A-F][a-f], and whitespaces [ ].
24 | * `enabled`: A boolean field which enables or disables the patch
25 | * `required`: A boolean field which determines if Lyptus should crash when a pattern for a given patch is not found or proceed to the next patch.
26 |
27 | ## 👋 Acknowledgements
28 |
29 | This project makes use of the following open source projects:
30 |
31 | - [spdlog](https://github.com/gabime/spdlog)
32 | - [JSON for Modern C++](https://github.com/nlohmann/json)
33 |
34 | ## 📄 License
35 |
36 | This software is licensed under [BSD Zero Clause License], terms of which are available in [LICENSE.txt]
37 |
38 | [BSD Zero Clause License]: https://choosealicense.com/licenses/0bsd/
39 |
40 | [LICENSE.txt]: LICENSE.txt
41 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | Set-Location (Get-Item $PSScriptRoot)
2 |
3 | . ./KoalaBox/build.ps1 @args
4 |
5 | Build-Project
--------------------------------------------------------------------------------
/res/Lyptus.json:
--------------------------------------------------------------------------------
1 | {
2 | "logging": true,
3 | "patches": [
4 | {
5 | "name": "Force unconditional jump",
6 | "pattern": "ABC??123",
7 | "offset": 0,
8 | "replacement": "EB",
9 | "enabled": true,
10 | "required": false
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/src/lyptus/lyptus.cpp:
--------------------------------------------------------------------------------
1 | #include "lyptus.hpp"
2 | #include "patcher/patcher.hpp"
3 |
4 | #include "koalabox/config_parser/config_parser.hpp"
5 | #include "koalabox/loader/loader.hpp"
6 | #include "koalabox/util/util.hpp"
7 | #include "koalabox/win_util/win_util.hpp"
8 |
9 | #include
10 |
11 | namespace lyptus {
12 |
13 | Config config = {}; // NOLINT(cert-err58-cpp)
14 |
15 | void validate_config() {
16 | const auto contains_only = [](const String& string, const Set& whitelist) {
17 | return std::ranges::all_of(string.begin(), string.end(),
18 | [&](char symbol) {
19 | return whitelist.contains(symbol);
20 | }
21 | );
22 | };
23 |
24 | Set valid_replacement_chars{
25 | ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
26 | 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f',
27 | };
28 |
29 | Set valid_pattern_chars(valid_replacement_chars);
30 | valid_pattern_chars.insert({ '?' });
31 |
32 | for (const auto& patch: config.patches) {
33 | if (not contains_only(patch.pattern, valid_pattern_chars)) {
34 | util::panic("Patch '{}' contains invalid pattern", patch.name);
35 | }
36 |
37 | if (not contains_only(patch.replacement, valid_replacement_chars)) {
38 | util::panic("Patch '{}' contains invalid replacement", patch.name);
39 | }
40 | }
41 | }
42 |
43 | void init(const HMODULE& self_module) {
44 | DisableThreadLibraryCalls(self_module);
45 |
46 | const auto self_directory = loader::get_module_dir(self_module);
47 |
48 | config = config_parser::parse(self_directory / PROJECT_NAME".json");
49 |
50 | validate_config();
51 |
52 | if (config.logging) {
53 | logger = file_logger::create(self_directory / PROJECT_NAME".log");
54 | }
55 |
56 | logger->info("🐨 Lyptus 🎋 v{}", PROJECT_VERSION);
57 |
58 | const auto process_handle = win_util::get_module_handle(nullptr);
59 | const auto process_info = win_util::get_module_info(process_handle);
60 |
61 | for (const auto& patch: config.patches) {
62 | if (not patch.enabled) {
63 | continue;
64 | }
65 |
66 | const auto address = patcher::find_pattern_address(process_info, patch);
67 |
68 | if (address == nullptr) {
69 | if (patch.required) {
70 | util::panic("Pattern for required patch '{}' was not found", patch.name);
71 | } else {
72 | continue;
73 | }
74 | }
75 |
76 | patcher::patch_memory(address, patch);
77 |
78 | logger->info("🍀 Patch '{}' was successfully applied", patch.name);
79 | }
80 |
81 | logger->info("🚀 Initialization complete");
82 | }
83 |
84 | void shutdown() {
85 | logger->info("💀 Shutdown complete");
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/lyptus/lyptus.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "koalabox/koalabox.hpp"
4 |
5 | namespace lyptus {
6 |
7 | using namespace koalabox;
8 |
9 | struct Patch {
10 | String name;
11 | String pattern;
12 | int offset = 0;
13 | String replacement;
14 | bool enabled = true;
15 | bool required = false;
16 |
17 | NLOHMANN_DEFINE_TYPE_INTRUSIVE(Patch, name, pattern, offset, replacement, enabled, required)
18 | };
19 |
20 | struct Config {
21 | bool logging = false;
22 | Vector patches;
23 |
24 | NLOHMANN_DEFINE_TYPE_INTRUSIVE(Config, logging, patches)
25 | };
26 |
27 | extern Config config;
28 |
29 | void init(const HMODULE& module);
30 |
31 | void shutdown();
32 |
33 | }
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "lyptus/lyptus.hpp"
2 |
3 | [[maybe_unused]]
4 | BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) {
5 | if (reason == DLL_PROCESS_ATTACH) {
6 | lyptus::init(instance);
7 | } else if (reason == DLL_PROCESS_DETACH) {
8 | lyptus::shutdown();
9 | }
10 |
11 | return TRUE;
12 | }
13 |
--------------------------------------------------------------------------------
/src/patcher/patcher.cpp:
--------------------------------------------------------------------------------
1 | #include "patcher.hpp"
2 | #include "koalabox/util/util.hpp"
3 | #include "koalabox/win_util/win_util.hpp"
4 |
5 | #include
6 | #include
7 |
8 | namespace patcher {
9 |
10 | using namespace lyptus;
11 |
12 | struct PatternMask {
13 | [[maybe_unused]] String binary_pattern;
14 | [[maybe_unused]] String mask;
15 | };
16 |
17 | /**
18 | * Converts user-friendly hex pattern string into a byte array
19 | * and generates corresponding string mask
20 | */
21 | PatternMask get_pattern_and_mask(String pattern) {
22 | // Remove whitespaces
23 | pattern = std::regex_replace(pattern, std::regex("\\s+"), "");
24 |
25 | // Convert hex to binary
26 | std::stringstream patternStream;
27 | std::stringstream maskStream;
28 | for (size_t i = 0; i < pattern.length(); i += 2) {
29 | std::string byteString = pattern.substr(i, 2);
30 |
31 | maskStream << (byteString == "??" ? '?' : 'x');
32 |
33 | // Handle wildcards ourselves, rest goes to strtol
34 | patternStream << (
35 | byteString == "??" ? '?' : (char) strtol(byteString.c_str(), nullptr, 16)
36 | );
37 | }
38 |
39 | return { patternStream.str(), maskStream.str() };
40 | }
41 |
42 | // Credit: superdoc1234
43 | // Source: https://www.unknowncheats.me/forum/1364641-post150.html
44 | char* find(PCSTR base_address, size_t mem_length, PCSTR pattern, PCSTR mask) {
45 | auto DataCompare = [](
46 | const auto* data, const auto* mask, const auto* ch_mask, auto ch_last, size_t i_end
47 | ) -> bool {
48 | if (data[i_end] != ch_last) return false;
49 | for (size_t i = 0; i <= i_end; ++i) {
50 | if (ch_mask[i] == 'x' && data[i] != mask[i]) {
51 | return false;
52 | }
53 | }
54 |
55 | return true;
56 | };
57 |
58 | auto iEnd = strlen(mask) - 1;
59 | auto chLast = pattern[iEnd];
60 |
61 | for (size_t i = 0; i < mem_length - strlen(mask); ++i) {
62 | if (DataCompare(base_address + i, pattern, mask, chLast, iEnd)) {
63 | return const_cast(base_address + i);
64 | }
65 | }
66 |
67 | return nullptr;
68 | }
69 |
70 | // Credit: Rake
71 | // Source: https://guidedhacking.com/threads/external-internal-pattern-scanning-guide.14112/
72 | char* scan_internal(PCSTR pMemory, size_t length, String pattern) {
73 | char* match = nullptr;
74 | MEMORY_BASIC_INFORMATION mbi{};
75 |
76 | auto[binaryPattern, mask] = get_pattern_and_mask(std::move(pattern));
77 |
78 | auto current_region = pMemory;
79 | do {
80 | // Skip irrelevant code regions
81 | auto result = VirtualQuery((LPCVOID) current_region, &mbi, sizeof(mbi));
82 | if (result && mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS) {
83 | match = find(current_region, mbi.RegionSize, binaryPattern.c_str(), mask.c_str());
84 |
85 | if (match) {
86 | break;
87 | }
88 | }
89 |
90 | current_region += mbi.RegionSize;
91 | } while (current_region < pMemory + length);
92 |
93 | return match;
94 | }
95 |
96 | // Source: https://gist.github.com/xsleonard/7341172
97 | unsigned char* hex_str_to_bytes(const char* hex_str) {
98 | size_t len = strlen(hex_str);
99 | if (len % 2 != 0) {
100 | util::panic(__func__, "Hex string must have even number of characters");
101 | }
102 | size_t final_len = len / 2;
103 | auto* data = (unsigned char*) malloc((final_len + 1) * sizeof(char));
104 | for (size_t i = 0, j = 0; j < final_len; i += 2, j++) {
105 | data[j] = (hex_str[i] % 32 + 9) % 25 * 16 + (hex_str[i + 1] % 32 + 9) % 25;
106 | }
107 | data[final_len] = '\0';
108 | return data;
109 | }
110 |
111 | char* find_pattern_address(const MODULEINFO& process_info, const Patch& patch) {
112 | const auto t1 = std::chrono::high_resolution_clock::now();
113 | const auto address = scan_internal(
114 | static_cast(process_info.lpBaseOfDll),
115 | process_info.SizeOfImage,
116 | patch.pattern
117 | );
118 | const auto t2 = std::chrono::high_resolution_clock::now();
119 |
120 | const double elapsedTime = std::chrono::duration(t2 - t1).count();
121 |
122 | if (address == nullptr) {
123 | logger->error(
124 | "Failed to find address of '{}'. Search time: {:.2f} ms",
125 | patch.name,
126 | elapsedTime
127 | );
128 | } else {
129 | logger->debug(
130 | "'{}' address: {}. Search time: {:.2f} ms",
131 | patch.name,
132 | fmt::ptr(address),
133 | elapsedTime
134 | );
135 | }
136 |
137 | return address;
138 | }
139 |
140 | void patch_memory(char* address, const Patch& patch) {
141 | const auto replacement = std::regex_replace(patch.replacement, std::regex("\\s+"), "");
142 | const auto bytes = hex_str_to_bytes(replacement.c_str());
143 |
144 | win_util::write_process_memory(
145 | ::GetCurrentProcess(),
146 | address + patch.offset,
147 | bytes,
148 | patch.replacement.length() / 2
149 | );
150 |
151 | delete bytes;
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/patcher/patcher.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "lyptus/lyptus.hpp"
4 |
5 | namespace patcher {
6 |
7 | using namespace lyptus;
8 |
9 | char* find_pattern_address(const MODULEINFO& process_info, const Patch& patch);
10 |
11 | void patch_memory(char* address, const Patch& patch);
12 |
13 | }
--------------------------------------------------------------------------------
/src/pch.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "koalabox/pch.hpp"
4 |
5 | #include "3rd_party/json.hpp"
6 |
7 | #include "koalabox/config_parser/config_parser.hpp"
8 | #include "koalabox/file_logger/file_logger.hpp"
9 | #include "koalabox/util/util.hpp"
10 | #include "koalabox/win_util/win_util.hpp"
11 |
--------------------------------------------------------------------------------
/vcpkg.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lyptus",
3 | "version": "0.0.0",
4 | "license": "0BSD",
5 | "dependencies": [
6 | "spdlog",
7 | "nlohmann-json"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------