├── .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 | 88 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 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 | --------------------------------------------------------------------------------