Repository: ItzSomebody/Radon Branch: master Commit: 7d3e8719afdb Files: 203 Total size: 684.8 KB Directory structure: gitextract__kzzqxxi/ ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle ├── docs/ │ ├── changelog.md │ ├── exclusions.md │ └── index.md ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── xyz.itzsomebody.codegen/ │ ├── README.md │ ├── build.gradle │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── xyz/ │ │ └── itzsomebody/ │ │ └── codegen/ │ │ ├── BytecodeBlock.java │ │ ├── GenerationContext.java │ │ ├── Utils.java │ │ ├── WrappedHandle.java │ │ ├── WrappedType.java │ │ ├── exceptions/ │ │ │ └── UncompilableNodeException.java │ │ ├── expressions/ │ │ │ ├── IRExpression.java │ │ │ ├── IRExpressions.java │ │ │ ├── IRVariable.java │ │ │ ├── flow/ │ │ │ │ ├── IRFlowStructure.java │ │ │ │ ├── IRForStructure.java │ │ │ │ ├── IRIfStructure.java │ │ │ │ ├── IRSwitchStructure.java │ │ │ │ ├── IRSynchronizedStructure.java │ │ │ │ ├── IRTryCatchStructure.java │ │ │ │ └── IRWhileStructure.java │ │ │ └── predefined/ │ │ │ ├── IRArithmeticExpression.java │ │ │ ├── IRArrayLengthExpression.java │ │ │ ├── IRCastExpression.java │ │ │ ├── IRConstantExpression.java │ │ │ ├── IRGetArrayElementExpression.java │ │ │ ├── IRGetFieldExpression.java │ │ │ ├── IRInstanceOfExpression.java │ │ │ ├── IRInvocationExpression.java │ │ │ ├── IRInvokeDynamicExpression.java │ │ │ ├── IRNegateExpression.java │ │ │ ├── IRNewArrayExpression.java │ │ │ ├── IRNewInstanceExpression.java │ │ │ ├── IRReturnExpression.java │ │ │ ├── IRSetArrayElementExpression.java │ │ │ ├── IRSetFieldExpression.java │ │ │ ├── IRSetVariableExpression.java │ │ │ └── IRThrowExceptionExpression.java │ │ └── instructions/ │ │ ├── BytecodeLabel.java │ │ ├── CompilableNode.java │ │ ├── ConstantNode.java │ │ ├── FieldAccessNode.java │ │ ├── InvokeDynamicNode.java │ │ ├── InvokeNode.java │ │ ├── JumpNode.java │ │ ├── NewArrayNode.java │ │ ├── RegisterNode.java │ │ ├── SimpleNode.java │ │ ├── SwitchNode.java │ │ └── TypeNode.java │ └── test/ │ └── java/ │ └── xyz/ │ └── itzsomebody/ │ └── codegen/ │ ├── UtilsTester.java │ ├── WrappedTypeTester.java │ ├── expressions/ │ │ ├── IRVariableTester.java │ │ └── predefined/ │ │ ├── IRArithmeticExpressionTester.java │ │ ├── IRArrayLengthTester.java │ │ ├── IRCastExpressionTester.java │ │ ├── IRConstantTester.java │ │ ├── IRGetArrayElementExpressionTester.java │ │ ├── IRGetFieldExpressionTester.java │ │ ├── IRInstanceOfExpressionTester.java │ │ ├── IRInvocationExpressionTester.java │ │ ├── IRInvokeDynamicExpressionTester.java │ │ ├── IRNegateExpressionTester.java │ │ ├── IRNewArrayExpressionTester.java │ │ ├── IRNewInstanceExpressionTester.java │ │ ├── IRReturnExpressionTester.java │ │ ├── IRSetArrayElementExpressionTester.java │ │ ├── IRSetFieldExpressionTester.java │ │ └── IRSetVariableExpressionTester.java │ └── instructions/ │ ├── BytecodeLabelTester.java │ ├── ConstantNodeTester.java │ ├── FieldAccessNodeTester.java │ ├── InvokeDynamicNodeTester.java │ ├── InvokeNodeTester.java │ ├── NewArrayNodeTester.java │ └── TypeNodeTester.java ├── xyz.itzsomebody.commons/ │ ├── README.md │ ├── build.gradle │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── xyz/ │ │ └── itzsomebody/ │ │ └── commons/ │ │ ├── InsnListModifier.java │ │ ├── MaxLocalsUpdater.java │ │ ├── analysis/ │ │ │ ├── callgraph/ │ │ │ │ └── CallGraphAnalyzer.java │ │ │ ├── cfg/ │ │ │ │ └── CFGAnalyzer.java │ │ │ └── frame/ │ │ │ └── FrameAnalyzer.java │ │ └── matcher/ │ │ ├── InstructionMatcher.java │ │ ├── InstructionPattern.java │ │ └── rules/ │ │ ├── AccessFieldRule.java │ │ ├── DoubleConstRule.java │ │ ├── FloatConstRule.java │ │ ├── InstructionRule.java │ │ ├── IntConstRule.java │ │ ├── InvocationRule.java │ │ ├── LongConstRule.java │ │ ├── OpcodeRule.java │ │ └── WildcardRule.java │ └── test/ │ └── java/ │ └── xyz/ │ └── itzsomebody/ │ └── commons/ │ ├── InsnListModifierTester.java │ ├── MaxLocalsUpdaterTester.java │ ├── TestingUtils.java │ └── matcher/ │ ├── InstructionMatcherTester.java │ └── rules/ │ ├── AccessFieldRuleTester.java │ ├── DoubleConstRuleTester.java │ ├── FloatConstRuleTester.java │ ├── IntConstRuleTester.java │ ├── InvocationRuleTester.java │ └── LongConstRuleTester.java ├── xyz.itzsomebody.radon/ │ ├── build.gradle │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── xyz/ │ │ │ └── itzsomebody/ │ │ │ └── radon/ │ │ │ ├── Radon.java │ │ │ ├── RadonConstants.java │ │ │ ├── RadonMain.java │ │ │ ├── cli/ │ │ │ │ ├── CmdArgsParser.java │ │ │ │ └── CmdSwitch.java │ │ │ ├── config/ │ │ │ │ ├── ConfigurationParser.java │ │ │ │ ├── DictionaryDeserializer.java │ │ │ │ ├── ExclusionsDeserializer.java │ │ │ │ ├── ObfConfig.java │ │ │ │ └── TransformerDeserializer.java │ │ │ ├── dictionaries/ │ │ │ │ ├── Dictionary.java │ │ │ │ ├── DictionaryFactory.java │ │ │ │ └── defined/ │ │ │ │ ├── AlphaNumericDictionary.java │ │ │ │ ├── AlphabeticalDictionary.java │ │ │ │ ├── CustomCharsetDictionary.java │ │ │ │ ├── RandomUnicodeDictionary.java │ │ │ │ ├── SpacesDictionary.java │ │ │ │ └── UnrecognizedDictionary.java │ │ │ ├── exceptions/ │ │ │ │ ├── FatalRadonException.java │ │ │ │ ├── MissingClassException.java │ │ │ │ ├── MissingResourceException.java │ │ │ │ └── PreventableRadonException.java │ │ │ ├── exclusions/ │ │ │ │ ├── Exclusion.java │ │ │ │ └── ExclusionManager.java │ │ │ ├── transformers/ │ │ │ │ ├── Transformer.java │ │ │ │ ├── Transformers.java │ │ │ │ ├── exploiter/ │ │ │ │ │ └── ExploiterTransformer.java │ │ │ │ ├── flow/ │ │ │ │ │ └── FlowTransformer.java │ │ │ │ ├── math/ │ │ │ │ │ └── NumberTransformer.java │ │ │ │ ├── misc/ │ │ │ │ │ ├── AddBridgeAccess.java │ │ │ │ │ ├── AddDeprecatedAccess.java │ │ │ │ │ ├── AddSyntheticAccess.java │ │ │ │ │ ├── AddTrashClasses.java │ │ │ │ │ ├── AntiDebugger.java │ │ │ │ │ ├── ExpirationKillSwitch.java │ │ │ │ │ ├── Packer.java │ │ │ │ │ ├── Renamer.java │ │ │ │ │ ├── ResourceRenamer.java │ │ │ │ │ ├── ScrambleLineNumbers.java │ │ │ │ │ ├── ShuffleMembers.java │ │ │ │ │ └── Watermarker.java │ │ │ │ ├── references/ │ │ │ │ │ └── ReferenceTransformer.java │ │ │ │ ├── shrinker/ │ │ │ │ │ ├── RemoveDeprecatedAccess.java │ │ │ │ │ ├── RemoveInnerClassesAttribute.java │ │ │ │ │ ├── RemoveInvisibleAnnotations.java │ │ │ │ │ ├── RemoveInvisibleParameterAnnotations.java │ │ │ │ │ ├── RemoveInvisibleTypeAnnotations.java │ │ │ │ │ ├── RemoveLineNumbers.java │ │ │ │ │ ├── RemoveLocalVariableTable.java │ │ │ │ │ ├── RemoveOuterMethodAttribute.java │ │ │ │ │ ├── RemoveSignatureAttribute.java │ │ │ │ │ ├── RemoveSourceDebugAttribute.java │ │ │ │ │ ├── RemoveSourceFileAttribute.java │ │ │ │ │ ├── RemoveSyntheticAccessAttribute.java │ │ │ │ │ ├── RemoveUnknownAttributes.java │ │ │ │ │ ├── RemoveVisibleAnnotations.java │ │ │ │ │ ├── RemoveVisibleParameterAnnotations.java │ │ │ │ │ ├── RemoveVisibleTypeAnnotations.java │ │ │ │ │ └── ShrinkerTransformer.java │ │ │ │ └── strings/ │ │ │ │ ├── AESPCBCEncryptor.java │ │ │ │ ├── AESPCBCStringEncryption.java │ │ │ │ ├── StaticFieldStrPool.java │ │ │ │ ├── Str2Base64Encoding.java │ │ │ │ └── StringTransformer.java │ │ │ └── utils/ │ │ │ ├── IOUtils.java │ │ │ ├── JarLoader.java │ │ │ ├── JarWriter.java │ │ │ ├── RandomUtils.java │ │ │ ├── asm/ │ │ │ │ ├── ASMUtils.java │ │ │ │ ├── ClassWrapper.java │ │ │ │ ├── FieldWrapper.java │ │ │ │ ├── FieldWrappers.java │ │ │ │ ├── MethodWrapper.java │ │ │ │ ├── MethodWrappers.java │ │ │ │ ├── RadonClassWriter.java │ │ │ │ ├── RadonRemapper.java │ │ │ │ └── ResourceNameRemapper.java │ │ │ └── logging/ │ │ │ ├── RadonConsoleHandler.java │ │ │ └── RadonLogger.java │ │ └── resources/ │ │ ├── asm-license.txt │ │ ├── jackson-license.txt │ │ └── radon-license.txt │ └── test/ │ └── java/ │ └── me/ │ └── itzsomebody/ │ └── radon/ │ └── transformers/ │ └── TransformersTest.java └── xyz.itzsomebody.radon.template/ ├── build.gradle └── src/ ├── README.md └── main/ └── java/ └── xyz/ └── itzsomebody/ └── radon/ └── templates/ └── string/ └── AESPCBCDecryptor.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = space insert_final_newline = false max_line_length = 120 tab_width = 4 ij_continuation_indent_size = 8 ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on ij_formatter_tags_enabled = false ij_smart_tabs = false ij_wrap_on_typing = false [*.java] ij_java_align_consecutive_assignments = false ij_java_align_consecutive_variable_declarations = false ij_java_align_group_field_declarations = false ij_java_align_multiline_annotation_parameters = false ij_java_align_multiline_array_initializer_expression = false ij_java_align_multiline_assignment = false ij_java_align_multiline_binary_operation = false ij_java_align_multiline_chained_methods = false ij_java_align_multiline_extends_list = false ij_java_align_multiline_for = true ij_java_align_multiline_method_parentheses = false ij_java_align_multiline_parameters = true ij_java_align_multiline_parameters_in_calls = false ij_java_align_multiline_parenthesized_expression = false ij_java_align_multiline_records = true ij_java_align_multiline_resources = true ij_java_align_multiline_ternary_operation = false ij_java_align_multiline_text_blocks = false ij_java_align_multiline_throws_list = false ij_java_align_subsequent_simple_methods = false ij_java_align_throws_keyword = false ij_java_annotation_parameter_wrap = off ij_java_array_initializer_new_line_after_left_brace = false ij_java_array_initializer_right_brace_on_new_line = false ij_java_array_initializer_wrap = off ij_java_assert_statement_colon_on_next_line = false ij_java_assert_statement_wrap = off ij_java_assignment_wrap = off ij_java_binary_operation_sign_on_next_line = false ij_java_binary_operation_wrap = off ij_java_blank_lines_after_anonymous_class_header = 0 ij_java_blank_lines_after_class_header = 0 ij_java_blank_lines_after_imports = 1 ij_java_blank_lines_after_package = 1 ij_java_blank_lines_around_class = 1 ij_java_blank_lines_around_field = 0 ij_java_blank_lines_around_field_in_interface = 0 ij_java_blank_lines_around_initializer = 1 ij_java_blank_lines_around_method = 1 ij_java_blank_lines_around_method_in_interface = 1 ij_java_blank_lines_before_class_end = 0 ij_java_blank_lines_before_imports = 1 ij_java_blank_lines_before_method_body = 0 ij_java_blank_lines_before_package = 0 ij_java_block_brace_style = end_of_line ij_java_block_comment_at_first_column = true ij_java_call_parameters_new_line_after_left_paren = false ij_java_call_parameters_right_paren_on_new_line = false ij_java_call_parameters_wrap = off ij_java_case_statement_on_separate_line = true ij_java_catch_on_new_line = false ij_java_class_annotation_wrap = split_into_lines ij_java_class_brace_style = end_of_line ij_java_class_count_to_use_import_on_demand = 5 ij_java_class_names_in_javadoc = 1 ij_java_do_not_indent_top_level_class_members = false ij_java_do_not_wrap_after_single_annotation = false ij_java_do_while_brace_force = never ij_java_doc_add_blank_line_after_description = true ij_java_doc_add_blank_line_after_param_comments = false ij_java_doc_add_blank_line_after_return = false ij_java_doc_add_p_tag_on_empty_lines = true ij_java_doc_align_exception_comments = true ij_java_doc_align_param_comments = true ij_java_doc_do_not_wrap_if_one_line = false ij_java_doc_enable_formatting = true ij_java_doc_enable_leading_asterisks = true ij_java_doc_indent_on_continuation = false ij_java_doc_keep_empty_lines = true ij_java_doc_keep_empty_parameter_tag = true ij_java_doc_keep_empty_return_tag = true ij_java_doc_keep_empty_throws_tag = true ij_java_doc_keep_invalid_tags = true ij_java_doc_param_description_on_new_line = false ij_java_doc_preserve_line_breaks = false ij_java_doc_use_throws_not_exception_tag = true ij_java_else_on_new_line = false ij_java_entity_dd_suffix = EJB ij_java_entity_eb_suffix = Bean ij_java_entity_hi_suffix = Home ij_java_entity_lhi_prefix = Local ij_java_entity_lhi_suffix = Home ij_java_entity_li_prefix = Local ij_java_entity_pk_class = java.lang.String ij_java_entity_vo_suffix = VO ij_java_enum_constants_wrap = off ij_java_extends_keyword_wrap = off ij_java_extends_list_wrap = off ij_java_field_annotation_wrap = split_into_lines ij_java_finally_on_new_line = false ij_java_for_brace_force = never ij_java_for_statement_new_line_after_left_paren = false ij_java_for_statement_right_paren_on_new_line = false ij_java_for_statement_wrap = off ij_java_generate_final_locals = false ij_java_generate_final_parameters = false ij_java_if_brace_force = never ij_java_imports_layout = *,|,javax.**,java.**,|,$* ij_java_indent_case_from_switch = true ij_java_insert_inner_class_imports = false ij_java_insert_override_annotation = true ij_java_keep_blank_lines_before_right_brace = 2 ij_java_keep_blank_lines_between_package_declaration_and_header = 2 ij_java_keep_blank_lines_in_code = 2 ij_java_keep_blank_lines_in_declarations = 2 ij_java_keep_control_statement_in_one_line = true ij_java_keep_first_column_comment = true ij_java_keep_indents_on_empty_lines = false ij_java_keep_line_breaks = true ij_java_keep_multiple_expressions_in_one_line = false ij_java_keep_simple_blocks_in_one_line = false ij_java_keep_simple_classes_in_one_line = false ij_java_keep_simple_lambdas_in_one_line = false ij_java_keep_simple_methods_in_one_line = false ij_java_label_indent_absolute = false ij_java_label_indent_size = 0 ij_java_lambda_brace_style = end_of_line ij_java_layout_static_imports_separately = true ij_java_line_comment_add_space = false ij_java_line_comment_at_first_column = true ij_java_message_dd_suffix = EJB ij_java_message_eb_suffix = Bean ij_java_method_annotation_wrap = split_into_lines ij_java_method_brace_style = end_of_line ij_java_method_call_chain_wrap = off ij_java_method_parameters_new_line_after_left_paren = false ij_java_method_parameters_right_paren_on_new_line = false ij_java_method_parameters_wrap = off ij_java_modifier_list_wrap = false ij_java_names_count_to_use_import_on_demand = 3 ij_java_new_line_after_lparen_in_record_header = false ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* ij_java_parameter_annotation_wrap = off ij_java_parentheses_expression_new_line_after_left_paren = false ij_java_parentheses_expression_right_paren_on_new_line = false ij_java_place_assignment_sign_on_next_line = false ij_java_prefer_longer_names = true ij_java_prefer_parameters_wrap = false ij_java_record_components_wrap = normal ij_java_repeat_synchronized = true ij_java_replace_instanceof_and_cast = false ij_java_replace_null_check = true ij_java_replace_sum_lambda_with_method_ref = true ij_java_resource_list_new_line_after_left_paren = false ij_java_resource_list_right_paren_on_new_line = false ij_java_resource_list_wrap = off ij_java_rparen_on_new_line_in_record_header = false ij_java_session_dd_suffix = EJB ij_java_session_eb_suffix = Bean ij_java_session_hi_suffix = Home ij_java_session_lhi_prefix = Local ij_java_session_lhi_suffix = Home ij_java_session_li_prefix = Local ij_java_session_si_suffix = Service ij_java_space_after_closing_angle_bracket_in_type_argument = false ij_java_space_after_colon = true ij_java_space_after_comma = true ij_java_space_after_comma_in_type_arguments = true ij_java_space_after_for_semicolon = true ij_java_space_after_quest = true ij_java_space_after_type_cast = true ij_java_space_before_annotation_array_initializer_left_brace = false ij_java_space_before_annotation_parameter_list = false ij_java_space_before_array_initializer_left_brace = false ij_java_space_before_catch_keyword = true ij_java_space_before_catch_left_brace = true ij_java_space_before_catch_parentheses = true ij_java_space_before_class_left_brace = true ij_java_space_before_colon = true ij_java_space_before_colon_in_foreach = true ij_java_space_before_comma = false ij_java_space_before_do_left_brace = true ij_java_space_before_else_keyword = true ij_java_space_before_else_left_brace = true ij_java_space_before_finally_keyword = true ij_java_space_before_finally_left_brace = true ij_java_space_before_for_left_brace = true ij_java_space_before_for_parentheses = true ij_java_space_before_for_semicolon = false ij_java_space_before_if_left_brace = true ij_java_space_before_if_parentheses = true ij_java_space_before_method_call_parentheses = false ij_java_space_before_method_left_brace = true ij_java_space_before_method_parentheses = false ij_java_space_before_opening_angle_bracket_in_type_parameter = false ij_java_space_before_quest = true ij_java_space_before_switch_left_brace = true ij_java_space_before_switch_parentheses = true ij_java_space_before_synchronized_left_brace = true ij_java_space_before_synchronized_parentheses = true ij_java_space_before_try_left_brace = true ij_java_space_before_try_parentheses = true ij_java_space_before_type_parameter_list = false ij_java_space_before_while_keyword = true ij_java_space_before_while_left_brace = true ij_java_space_before_while_parentheses = true ij_java_space_inside_one_line_enum_braces = false ij_java_space_within_empty_array_initializer_braces = false ij_java_space_within_empty_method_call_parentheses = false ij_java_space_within_empty_method_parentheses = false ij_java_spaces_around_additive_operators = true ij_java_spaces_around_assignment_operators = true ij_java_spaces_around_bitwise_operators = true ij_java_spaces_around_equality_operators = true ij_java_spaces_around_lambda_arrow = true ij_java_spaces_around_logical_operators = true ij_java_spaces_around_method_ref_dbl_colon = false ij_java_spaces_around_multiplicative_operators = true ij_java_spaces_around_relational_operators = true ij_java_spaces_around_shift_operators = true ij_java_spaces_around_type_bounds_in_type_parameters = true ij_java_spaces_around_unary_operator = false ij_java_spaces_within_angle_brackets = false ij_java_spaces_within_annotation_parentheses = false ij_java_spaces_within_array_initializer_braces = false ij_java_spaces_within_braces = false ij_java_spaces_within_brackets = false ij_java_spaces_within_cast_parentheses = false ij_java_spaces_within_catch_parentheses = false ij_java_spaces_within_for_parentheses = false ij_java_spaces_within_if_parentheses = false ij_java_spaces_within_method_call_parentheses = false ij_java_spaces_within_method_parentheses = false ij_java_spaces_within_parentheses = false ij_java_spaces_within_switch_parentheses = false ij_java_spaces_within_synchronized_parentheses = false ij_java_spaces_within_try_parentheses = false ij_java_spaces_within_while_parentheses = false ij_java_special_else_if_treatment = true ij_java_subclass_name_suffix = Impl ij_java_ternary_operation_signs_on_next_line = false ij_java_ternary_operation_wrap = off ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = off ij_java_throws_list_wrap = off ij_java_use_external_annotations = false ij_java_use_fq_class_names = false ij_java_use_relative_indents = false ij_java_use_single_class_imports = true ij_java_variable_annotation_wrap = off ij_java_visibility = public ij_java_while_brace_force = never ij_java_while_on_new_line = false ij_java_wrap_comments = false ij_java_wrap_first_method_in_call_chain = false ij_java_wrap_long_lines = false ================================================ FILE: .gitignore ================================================ # Compiled class file *.class # Gradle .gradle/ build/ # Eclipse .setup/ bin/ .classpath .project # IntelliJ *.iml .idea/ out/ # VS Code .settings/ # Radon radon.log radon.log.lck ================================================ FILE: .travis.yml ================================================ language: java install: true dist: trusty jdk: - oraclejdk11 script: - ./gradlew build ================================================ FILE: CONTRIBUTING.md ================================================ # Radon Contribution Guide ## Table of Contents * [GitHub](#github) * [Issue Reports](#issue-reports) * [Pull Requests](#pull-requests) * [Styleguides](#styleguides) * [Git Commit Messages](#git-commit-messages) * [Java Styleguide](#java-styleguide) * [Transformer Documentation](#transformer-documentation) ## GitHub ### Issue Reports Found an issue with Radon? Awesome. Make sure you read the following before reporting it: #### Before Submitting an Issue Report * **Check the FAQ in the readme**. Radon has had numerous "bugs/errors/issues" reported which were completely preventable due to configuration. * **Check if the issue has already been reported**. Should said issue already exist, add a comment on the issue rather than starting a new one. * **Check if you made a YAML error**. You can use an online YAML verifier like [this one](http://www.yamllint.com/) to catch errors quickly. * **If possible, please spend a little time debugging before reporting the issue!** This could save a ton of time for you and anyone who decides to fix the bug. If you are able to locate the precise issue in Radon's codebase, chances are a fix can be implemented much sooner. #### Submitting an Issue Report as a Bug All bugs are tracked as GitHub issues for organizational purposes. For that reason, please do not report bugs in the Discord and expect a fix as I am prone to forgetfulness. When opening a bug report, please make sure to follow the below: * **Use a clear and descriptive title**. * Example of a **good** title: "Using the FastInvokedynamic transformer on any Spigot plugin results in NPE from radon" * Example of a **good** title: "Adding an exclusion hangs the renamer" * Example of a **bad** title: "Adding an exclusions causes bug" * Example of a **bad** title: "Radon bug" * **Be as specific and descriptive as possible when describing the issue**. It really annoys me and other people when your description is vague. I should be able to understand exactly what the issue is with no questions asked. * **Be as detailed as you can when describing the expected behavior.** Same reason as above. * **Provide the git commit hash you build Radon from.** This allows me or anyone investigating the issue to instantly find the version of Radon you are using. Saying "latest" or similar will result in an instant close of your issue with no help provided. If you're not going to make an effort to make a proper report, then I'm not going to make an effort to help. * **Provide the exact configuration used in code blocks**. This means no blanking out lines and no screenshots. I apologize in advance if privacy is desired, but issues that could have been solved in 5 seconds have lasted multiple hours because people hid parts of their configuration while requesting help. * **Provide the relevant errors and exceptions in code blocks.** Please do not put screenshots here and make sure to put each error in its own markdown code block. Also, please make sure you specify when the error happens. * **Be as specific and detailed as possible when doing reproduction steps**. This is where some of the worst miscommunications have happened which resulted in a ton of wasted time. Please just put in a little effort so that I know *exactly* what you did. * **Attach / link what you attempted to obfuscate**. This is a mandatory for all software problems created by the obfuscation. If you are unable to attach or link the software you obfuscated, attach a proof-of-concept JAR which also causes the same issue to happen. If possible, please also provide the obfuscated output. Extra: [this video](https://www.youtube.com/watch?v=53zkBvL4ZB4&vl=en) by [LiveOverflow](https://github.com/LiveOverflow) and this [webpage](http://www.catb.org/esr/faqs/smart-questions.html) are good references for properly asking a question. #### Submitting an Issue Report as an Enhancement / Feature Request All enhancements and feature requests are tracked as GitHub issues for organizational purposes. When opening an enhancement / feature request, please make sure to follow the below: * **Use a clear and descriptive title**. Please also prefix the title with [Enhancement/FR] so there's no room for confusion. * Example of a **good** title: "[Enhancement] Use dynamic decryption methods for XXXX instead of YYYY" * Example of a **good** title: "[Feature Request] Transformer to flatten the CFG" * Example of a **bad** title: "suggestion" * Example of a **bad** title: "thing to make radon better" * **Provide an in-depth description of what the feature should do.** You need to be as descriptive as possible to the point where people shouldn't have to ask question to understand what the feature/enhancement will do. #### Pull Requests Pull requests should fulfill one of the following: * Spelling / grammatical errors in documentation, Javadocs, or markdown files. * Fix issues reported on the issue tracker. * Implement an enhancement / feature request on the issue tracker. * If a transformer is implemented, it needs to be added as an enum field to 1. `xyz.itzsomebody.radon.transformers.Transformers` and 2. (Optional) Be documented accordingly. * Update code or documentation to adhere to the specified style guides. * Replace poorly-written or spaghetti code with properly-written and thought-out code. The rules for guidelines are pretty simple: * Follow the style guides. * Fix your commits should status checks fail. * If the PR adds features / code, make sure you also appropriately document said additions. * No need to squash commits -- I will personally do that if I think it's necessary. ## Style guides #### Git Commit Messages * Use present tense. * Use the imperative mood. #### Java All Java code should adhere to the provided EditorConfig file. Even though the column limit is set to 120, feel free to ignore that. #### Markdown All markdown files are required to be hard-wrapped at 120 characters. The only exceptions are extremely long URLs and code snippets. ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================ # [Abandoned] Radon Java Bytecode Obfuscator ## Radon is no longer maintained It's important to note that Radon is intended for __***experimentation only***__. If your software breaks in production because you protected it with Radon then that is completely on you. If you have a quick question about how something works, you can join my [Discord](https://discord.gg/RfuxTea) server and ask. This project is **not** likely to be production-safe nor bug free. If you would like some pointers to production-safe (more or less) and less buggy Java bytecode obfuscators that are properly maintained, I would suggest one of these: * [Proguard](https://www.guardsquare.com/en/products/proguard) (mostly only class/method/field name obfuscation) * [Skidfuscator](https://github.com/terminalsin/skidfuscator-java-obfuscator) - [Discord](https://discord.gg/QJC9g8fBU9) * [Zelix KlassMaster](http://www.zelix.com/) Since we're on the topic of obfuscation, consider taking a look at [Recaf](https://github.com/Col-E/Recaf) ([Discord](https://discord.gg/Bya5HaA)) if you have not already. Recaf is actively maintained by the contributers to stay on top of a variety obfuscation techniques found in the wild. I would highly recommend learning to use Recaf for those who are into Java reverse-engineering. [Skidfuscator](https://github.com/terminalsin/skidfuscator-java-obfuscator) is probably one of the most promising Java bytecode obfuscation projects I have seen and has a much more sanely-managed codebase than most obfuscators do (including Radon). I would recommend anyone trying to get into Java obfuscation to spend time learning how Skidfuscator works. Another resource (slightly dated, but still a good amount of information) is GenericException's [SkidSuite](https://github.com/GenericException/SkidSuite) repo. Some common cheap obfuscation techniques that have become more common in the last few years are documented there which anyone who is interested in Java reverse-engineering should know. Additionally, here are some other obfuscators/protectors for Java that you could check out for fun or learning (though not necessarily I would recommend using are): * [Allatori](http://www.allatori.com/) - Commericial. Somewhat popular choice in industry. * [avaj](https://github.com/cg-dot/avaj) - FOSS. Has a nice way of generating decryption subroutines on string constants. Also has some CFG flattening which is always nice to see. * [BisGuard](http://www.bisguard.com/) - Commercial. Relies entirely on class encryption (last time I checked, at least) so protection has quite a bit of room for improvement. * [Bozar](https://github.com/vimasig/Bozar) - Points for FOSS. Has some cheap tricks that I have seen being used in the Minecraft community. * [Branchlock](https://branchlock.net/) - Commercial. Shows up a bit in the Minecraft community. * [Caesium](https://github.com/sim0n/Caesium) - FOSS. Has a transformer that implements a well-known HTML injection into any Java reverse-engineering tool that parses HTML tags. * [ClassGuard](https://zenofx.com/classguard/) - Commercial. Relies mostly on class encryption with hardcoded AES keys in native libs. Pretty easy IDA/Binary Ninja/Ghidra exercise if you want to flex on your blog on something. * [DashO](https://www.preemptive.com/products/dasho/overview) - Commercial. Shows up a bit in industry and has some interesting ideas (albeit probably outdated) in flow obfuscation. * [JBCO](http://www.sable.mcgill.ca/JBCO/) - FOSS. Some interesting flow obfuscation techniques that still work in modern Java. Based on the [Soot](https://github.com/soot-oss/soot) library which is also something worthwhile checking out. * [JObf](https://github.com/superblaubeere27/obfuscator) - FOSS. Pretty outdated. Some of the transformations done show up in the Minecraft community so it can be worthwhile spending a bit of time takinng a look at this. * [JObfuscator](https://www.pelock.com/products/jobfuscator) - Commericial. Never seen this used before so I cannot really give any comments. * [NeonObf](https://github.com/MoofMonkey/NeonObf) - Mostly points for FOSS. Made up of the easier to defeat obfuscation techniques. NeonObf is also the name inspiration for Radon. * [Obzcure](https://obzcu.re/) [Discord](https://discordapp.com/invite/fUCPxq8) (Dead) - Commericial. Web-based obfuscation service with some inspiration taken from Radon and [SkidSuite2](https://github.com/GenericException/SkidSuite/tree/master/archive/skidsuite-2). Used to go by the name "SpigotProtect" so you might see some Spigot plugins using the obfuscation from this product if you look around hard enough. * [Paramorphism](https://paramorphism.serenity.enterprises/) - [Discord](https://discordapp.com/invite/k9DPvEy) (Dead) - Commerical. Was one of the most unusual and unique obfuscators at the time it was an active project in that relied a lot more on the JVM's unusual way of loading JAR archives including zip entries with duplicated names and the [fake directory trick](https://github.com/x4e/fakedirectory). Used to be more commonly used before people started ripping ideas from Paramorphism. * [qProtect](https://mdma.dev/) - Commericial. Implements a lot of the more common obfuscation techiques into a single tool. Shows up a bit in the Minecraft community. * [Sandmark](http://sandmark.cs.arizona.edu) - FOSS. Really old obfuscator research project led by Christian Collberg at the University of Arizona. Some interesting ideas in watermarking are here and some of the flow obfuscation ideas are good. * [SkidSuite2](https://github.com/GenericException/SkidSuite/tree/master/archive/skidsuite-2) - FOSS. Some pretty basic obfuscation techniques, nothing too special. * [Stringer](https://jfxstore.com/stringer/) - Commercial. Pretty infamous for its complicated AES-based encryption/decryption routines and price. Does not really offer a whole lot of protection, but sometimes does show up in industry. * [yGuard](https://www.yworks.com/products/yguard) - FOSS. Functionally equivalent to ProGuard as far as I can tell. * [zProtect](https://zprotect.dev/) - [Discord](https://discord.com/invite/dnGKGuwvGH) - Commercial. Newer obfuscator. I have not seen any samples from it so I do not have an opinion on it. ## Build Instructions Run the following (and hope nothing breaks): ``` ./gradlew build ``` Or if you're on Windows: ``` gradlew.bat build ``` Should that somehow not work, use the following instead: ``` ./gradlew clean shadowJar ``` P.S. For those wondering why there aren't any prebuilt releases, if you can't figure out how to use Gradle, should you really be using an obfuscator? ;) [end of snarkiness] ## FAQ * **Q: Is this uncrackable/undeobfuscatable?** *A: No. Nothing is impossible to deobfuscate or reverse-engineer. Furthermore, Radon is far from being hard to deobfuscate. On a scale of 1 to 10 on how hard Radon is to deobfuscate, I'd say 2 in the best possible scenario.* * **Q: Why is this open-sourced?** *A: I made Radon as a way to experiment with obfuscation and to become familiar with the JVM bytecode instruction set and as a codebase if anyone wants to mess around. Furthermore, I strongly support the FOSS ideology.* * **Q: Doesn't Radon being open-sourced make it easier to deobfuscate?** *A: Probably.* * **Q: Can Spring apps be obfuscated with this?** *A: Out of the box, no. Starting from Radon 3, I will never add support for Spring or multiversion JARs.* * **Q: What does '... "org/somelib/TableFactoryBuilder" not found in classpath' mean?** *A: Radon internally determines how to construct certain entities in the classfile based on the class hierarchy of the JAR being obfuscated. For this reason, Radon needs access to library classes used by the project. Make sure you add the appropriate libraries so this doesn't show up.* * **Q: Can I use all transformers for maximum protection?** *A: You could, but you should note that it's very likely that the program will break and/or there will be a large overhead in file size and/or performance.* * **Q: Why do certain combinations of transformers break the program?** *A: Radon is intended to be an experimental project, not a commercial product protector. Not all features are meant to work together.* * **Q: What version of Java is required to run Radon 3?** *A: Java 11+.* * **Q: What version of Java is my software required to written in to work with Radon?** *A: Radon can theoretically obfuscate software written in any Java version provided that the `asm` library is compatible with the classfile version.* * **Q: Does Radon support Android?** *A: While the answer is technically yes, I will not provide support for issues pertaining to Android apps.* * **Q: Does Radon have Gradle, Maven, or Ant integration?** *A: No. You are more than welcome to make a PR to add such functionality if desired.* * **Q: Will there be a GUI for Radon 3?** *A: Yes, however, a GUI is very low on my priority list, so it might be awhile before one is actually made.* * **Q: Will there be a Radon 4?** *A: Probably not.* ## License GNU General Public License v3.0 (The cancer license) ================================================ FILE: build.gradle ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ plugins { id 'com.github.johnrengelman.shadow' version '5.1.0' } defaultTasks 'clean', 'test', 'build' ext { // ASM asmVer = '9.4' asm = 'org.ow2.asm:asm:' + asmVer asmAnalysis = 'org.ow2.asm:asm-analysis:' + asmVer asmCommons = 'org.ow2.asm:asm-commons:' + asmVer asmTree = 'org.ow2.asm:asm-tree:' + asmVer asmUtil = 'org.ow2.asm:asm-util:' + asmVer // junit junit = 'junit:junit:4.12' // Annotations annotations = 'org.jetbrains:annotations:20.1.0' // Jackson jackson = 'com.fasterxml.jackson.core:jackson-databind:2.12.2' // Java version javaVer = 11 } allprojects { // Project group and version group 'xyz.itzsomebody' version '3.0.0-SNAPSHOT' // Compile using UTF-8 encoding tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } repositories { mavenCentral() } } ================================================ FILE: docs/changelog.md ================================================ # Changelog ## 3.0.0 - Full rewrite There are multiple turning points with the release of Radon 3.0.0 compared to all previous versions of Radon. ### Differences between Radon 3 and previous versions * Radon 3 is written in Java 11. Every previous version of Radon was written in Java 8. * Some of Radon 3's features are not portable to different JVMs whereas every previous version of Radon was intended for HotSpot. * Radon 3 removes all "optimizers" from Radon 2. If you need some kind of optimization done, use ProGuard instead. * Compared to Radon 2, Radon 3 can be significantly more risky in how it performs transformations on bytecode. * Radon 2 uses the GitHub wiki for documentation of transformers and usage. Radon 3 has no usage guide and uses GitHub pages for documentation of transformers (however, the wiki will not be removed for ease of reference). * Radon 3 removes delegation for "shrinking" transformers via the above point. * Radon 3 adheres to a style guide (sort of) whereas no previous version of Radon has. * Radon 3 reimplements the exclusion system in a much more efficient matter. * Radon 3 introduces a high-level code generator to remove some reliance on ASMifier generated code. ================================================ FILE: docs/exclusions.md ================================================ # Exclusions **Note: You will need a basic understanding of internal class/method/field names to understand how Radon processes exclusions.** Exclusions in Radon are regex-based and are matched using the code below: ```java public boolean matches(String other, ExclusionType type) { if (type == ExclusionType.GLOBAL || type == exclusionType) { return true; } return invert != matcher.reset(other).matches(); } ``` **The use of `java.util.regex.Matcher#matches()` is intentional and should be considered whilst creating an exclusion.** * When **classes** are checked for exclusion, the internal name is passed into `other`. e.g. ```java // Check for java.lang.Object and java.lang.String Exclusion exclusion = new Exclusion("java/lang/(Object|String)"); System.out.println(exclusion.matches("java/lang/Object")); // true System.out.println(exclusion.matches("java/lang/String")); // true System.out.println(exclusion.matches("java/lang/String isEmpty()Z")); // false System.out.println(exclusion.matches("java/lang/Number")); // false ``` ```java // Check for all classes that start with "java.lang" in their internal name Exclusion exclusion = new Exclusion("java/lang.*"); System.out.println(exclusion.matches("java/lang/Object")); // true System.out.println(exclusion.matches("java/lang/String")); // true System.out.println(exclusion.matches("java/lang/String isEmpty()Z")); // true - be careful when playing with ".*" System.out.println(exclusion.matches("java/lang/Number")); // true ``` * When **methods** are checked for exclusion, ` ` is passed into `other`. e.g. ```java // Check for java.lang.String.isEmpty() Exclusion exclusion = new Exclusion("java/lang/String isEmpty\\(\\)Z"); System.out.println(exclusion.matches("java/lang/String isEmpty()Z")); // true System.out.println(exclusion.matches("java/lang/String toCharArray()[C")); // false ``` * When **fields** are checked for exclusion, ` ` is passed into `other`. e.g. ```java // Check for java.lang.System.out Exclusion exclusion = new Exclusion("java/lang/System out Ljava/io/PrintStream;"); System.out.println(exclusion.matches("java/lang/System out Ljava/lang/PrintStream;")); // true System.out.println(exclusion.matches("java/lang/System err Ljava/lang/PrintStream;")); // false ``` ================================================ FILE: docs/index.md ================================================ # Radon Java Obfuscator [![Build Status](https://travis-ci.org/ItzSomebody/Radon.svg?branch=master)](https://travis-ci.org/ItzSomebody/Radon) Welcome to the documentation page for the Radon Java bytecode obfuscator! Here you can find the documentation and various parts of stuff put into Radon's internals and transformers. * [Changelog](changelog.md) * [Exclusions](exclusions.md) * Transformers * TODO ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh # # Copyright 2015 the original author or authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin or MSYS, switch paths to Windows format before running java if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=`expr $i + 1` done case $i in 0) set -- ;; 1) set -- "$args0" ;; 2) set -- "$args0" "$args1" ;; 3) set -- "$args0" "$args1" "$args2" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: settings.gradle ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ rootProject.name = 'radon' include 'xyz.itzsomebody.codegen' include 'xyz.itzsomebody.radon' include 'xyz.itzsomebody.commons' include 'xyz.itzsomebody.radon.template' ================================================ FILE: xyz.itzsomebody.codegen/README.md ================================================ # CodeGen This module contains radon's bytecode code generation utility. This is intended to reduce some of the heavy reliance on the asm-tree API and ASMifier, and is based on the airlift bytecode generation library. ================================================ FILE: xyz.itzsomebody.codegen/build.gradle ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ plugins { id 'java' } sourceCompatibility = javaVer dependencies { implementation annotations implementation asm implementation asmTree testImplementation junit } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/BytecodeBlock.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import org.objectweb.asm.tree.InsnList; import xyz.itzsomebody.codegen.expressions.predefined.IRReturnExpression; import xyz.itzsomebody.codegen.instructions.CompilableNode; import xyz.itzsomebody.codegen.instructions.SimpleNode; import java.util.ArrayList; import java.util.List; public class BytecodeBlock { private final List nodes = new ArrayList<>(); public BytecodeBlock append(BytecodeBlock block) { nodes.addAll(block.nodes); return this; } public BytecodeBlock append(CompilableNode node) { nodes.add(node); return this; } public InsnList compile() { var insns = new InsnList(); nodes.forEach(node -> insns.add(node.getNode())); return insns; } public BytecodeBlock voidReturn(){ nodes.add(SimpleNode.RETURN_VOID); return this; } public List getNodes() { return nodes; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/GenerationContext.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import xyz.itzsomebody.codegen.expressions.IRVariable; public class GenerationContext { private int slotOffset = 0; public void setSlotOffset(int slotOffset) { this.slotOffset = slotOffset; } public IRVariable newVariable(WrappedType type) { var variable = new IRVariable(type, slotOffset); slotOffset += type.getType().getSize(); return variable; } public IRVariable newVariable(Class clazz) { return newVariable(WrappedType.from(clazz)); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/Utils.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import org.objectweb.asm.Type; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.codegen.instructions.BytecodeLabel; import xyz.itzsomebody.codegen.instructions.ConstantNode; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class Utils { public static List wrapMethodNodeParameters(MethodNode methodNode) { var wrappedTypes = new ArrayList(); List.of(Type.getArgumentTypes(methodNode.desc)).forEach(type -> wrappedTypes.add(new WrappedType(type))); return wrappedTypes; } public static List wrapMethodParameters(Method method) { var wrappedTypes = new ArrayList(); List.of(method.getParameterTypes()).forEach(clazz -> wrappedTypes.add(WrappedType.from(clazz))); return wrappedTypes; } public static List wrapConstructorParameters(Constructor constructor) { var wrappedTypes = new ArrayList(); List.of(constructor.getParameterTypes()).forEach(clazz -> wrappedTypes.add(WrappedType.from(clazz))); return wrappedTypes; } public static String unwrapMethodDescriptor(List parameterTypes, WrappedType returnType) { var sb = new StringBuilder("("); parameterTypes.forEach(type -> sb.append(type.unwrap())); sb.append(')').append(returnType.unwrap()); return sb.toString(); } public static ArrayList unwrapLabels(List wrappedLabels) { var unwrappedLabels = new ArrayList(wrappedLabels.size()); wrappedLabels.forEach(wrappedLabel -> unwrappedLabels.add(wrappedLabel.getLabel())); return unwrappedLabels; } public static Object[] unpackConstants(List constants) { var unpacked = new Object[constants.size()]; for (var i = 0; i < unpacked.length; i++) { unpacked[i] = constants.get(i).getValue(); } return unpacked; } public static WrappedType box(WrappedType primitive) { if (!primitive.isPrimitive()) { throw new IllegalArgumentException("Attempted to box non-primitive type: " + primitive); } switch (primitive.getSort()) { case Type.BOOLEAN: return WrappedType.from(Boolean.class); case Type.CHAR: return WrappedType.from(Character.class); case Type.BYTE: return WrappedType.from(Byte.class); case Type.SHORT: return WrappedType.from(Short.class); case Type.INT: return WrappedType.from(Integer.class); case Type.LONG: return WrappedType.from(Long.class); case Type.FLOAT: return WrappedType.from(Float.class); case Type.DOUBLE: return WrappedType.from(Double.class); default: throw new IllegalArgumentException("Unknown primitive type: " + primitive); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/WrappedHandle.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; public class WrappedHandle { private final int tag; private final WrappedType owner; private final String name; private final List parameterTypes; private final WrappedType returnType; public WrappedHandle(int tag, WrappedType owner, String name, List parameterTypes, WrappedType returnType) { this.tag = tag; this.owner = owner; this.name = name; this.parameterTypes = parameterTypes; this.returnType = returnType; } public int getTag() { return tag; } public WrappedType getOwner() { return owner; } public String getName() { return name; } public List getParameterTypes() { return parameterTypes; } public WrappedType getReturnType() { return returnType; } public Handle constructHandle() { return new Handle(tag, owner.getInternalName(), name, Utils.unwrapMethodDescriptor(parameterTypes, returnType), owner.isInterface()); } // Fields public static WrappedHandle getFieldHandle(WrappedType owner, String name, WrappedType type) { return new WrappedHandle(Opcodes.H_GETFIELD, owner, name, Collections.emptyList(), type); } public static WrappedHandle getFieldHandle(Field field) { return getFieldHandle(WrappedType.from(field.getDeclaringClass()), field.getName(), WrappedType.from(field.getType())); } public static WrappedHandle getStaticHandle(WrappedType owner, String name, WrappedType type) { return new WrappedHandle(Opcodes.H_GETSTATIC, owner, name, Collections.emptyList(), type); } public static WrappedHandle getStaticHandle(Field field) { return getFieldHandle(WrappedType.from(field.getDeclaringClass()), field.getName(), WrappedType.from(field.getType())); } public static WrappedHandle putFieldHandle(WrappedType owner, String name, WrappedType type) { return new WrappedHandle(Opcodes.H_PUTFIELD, owner, name, Collections.emptyList(), type); } public static WrappedHandle putFieldHandle(Field field) { return getFieldHandle(WrappedType.from(field.getDeclaringClass()), field.getName(), WrappedType.from(field.getType())); } public static WrappedHandle putStaticHandle(WrappedType owner, String name, WrappedType type) { return new WrappedHandle(Opcodes.H_PUTSTATIC, owner, name, Collections.emptyList(), type); } public static WrappedHandle putStaticHandle(Field field) { return getFieldHandle(WrappedType.from(field.getDeclaringClass()), field.getName(), WrappedType.from(field.getType())); } // Methods public static WrappedHandle getInvokeVirtualHandle(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new WrappedHandle(Opcodes.H_INVOKEVIRTUAL, owner, name, parameterTypes, returnType); } public static WrappedHandle getInvokeVirtualHandle(Method method) { return getInvokeVirtualHandle(WrappedType.from(method.getDeclaringClass()), method.getName(), Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } public static WrappedHandle getInvokeStaticHandle(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new WrappedHandle(Opcodes.H_INVOKESTATIC, owner, name, parameterTypes, returnType); } public static WrappedHandle getInvokeStaticHandle(Method method) { return getInvokeStaticHandle(WrappedType.from(method.getDeclaringClass()), method.getName(), Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } public static WrappedHandle getInvokeSpecialHandle(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new WrappedHandle(Opcodes.H_INVOKESPECIAL, owner, name, parameterTypes, returnType); } public static WrappedHandle getInvokeSpecialHandle(Method method) { return getInvokeSpecialHandle(WrappedType.from(method.getDeclaringClass()), method.getName(), Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } public static WrappedHandle getNewInvokeSpecialHandle(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new WrappedHandle(Opcodes.H_NEWINVOKESPECIAL, owner, name, parameterTypes, returnType); } public static WrappedHandle getNewInvokeSpecialHandle(Method method) { return getNewInvokeSpecialHandle(WrappedType.from(method.getDeclaringClass()), method.getName(), Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } public static WrappedHandle getInvokeInterfaceHandle(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new WrappedHandle(Opcodes.H_INVOKEVIRTUAL, owner, name, parameterTypes, returnType); } public static WrappedHandle getInvokeInterfaceHandle(Method method) { return getInvokeInterfaceHandle(WrappedType.from(method.getDeclaringClass()), method.getName(), Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/WrappedType.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; import java.util.HashMap; import java.util.Map; public class WrappedType { private static final Map> BOXED_TYPES = new HashMap<>() { { put(Type.getInternalName(Boolean.class), boolean.class); put(Type.getInternalName(Character.class), char.class); put(Type.getInternalName(Byte.class), byte.class); put(Type.getInternalName(Short.class), short.class); put(Type.getInternalName(Integer.class), int.class); put(Type.getInternalName(Float.class), float.class); put(Type.getInternalName(Long.class), long.class); put(Type.getInternalName(Double.class), double.class); } }; private static AbsentWrappedType absent; private final Type type; private final boolean isInterface; public WrappedType(Type type) { this.type = type; this.isInterface = false; } public WrappedType(Type type, boolean isInterface) { this.type = type; this.isInterface = isInterface; } public static AbsentWrappedType getAbsent() { if (absent == null) { absent = new AbsentWrappedType(); } return absent; } public Type getType() { return type; } public boolean isInterface() { return isInterface; } public int getSort() { return type.getSort(); } /** * For NEWARRAY instructions */ public int getNewArraySort() { switch (type.getSort()) { case Type.BOOLEAN: return Opcodes.T_BOOLEAN; case Type.CHAR: return Opcodes.T_CHAR; case Type.FLOAT: return Opcodes.T_FLOAT; case Type.DOUBLE: return Opcodes.T_DOUBLE; case Type.BYTE: return Opcodes.T_BYTE; case Type.SHORT: return Opcodes.T_SHORT; case Type.INT: return Opcodes.T_INT; case Type.LONG: return Opcodes.T_LONG; default: throw new UncompilableNodeException("Attempted to get primitive array type of " + this); } } public boolean isPrimitive() { switch (type.getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: case Type.FLOAT: case Type.LONG: case Type.DOUBLE: return true; default: return false; } } public WrappedType getPrimitiveType() { var primitiveClass = BOXED_TYPES.get(getInternalName()); if (primitiveClass == null) { throw new UncompilableNodeException("Attempted to get primitive type of " + this); } return WrappedType.from(primitiveClass); } public boolean isBoxed() { return BOXED_TYPES.containsKey(getInternalName()); } public boolean isArray() { return type.getSort() == Type.ARRAY; } public boolean isIntType() { var sort = getSort(); return (sort == Type.BOOLEAN) || (sort == Type.CHAR) || (sort == Type.BYTE) || (sort == Type.SHORT) || (sort == Type.INT); } public String unwrap() { if (type.getSort() == Type.OBJECT) { return 'L' + type.getInternalName() + ';'; } else { return type.getInternalName(); } } public String getInternalName() { return type.getInternalName(); } public String getClassName() { return type.getClassName(); } public static WrappedType fromClassName(String className, boolean isInterface) { StringBuilder internalName = new StringBuilder(); if (className.endsWith("[]")) { className = className.substring(0, className.length() - 2); internalName.append('['); } switch (className) { case "int": internalName.append("I"); break; case "long": internalName.append("J"); break; case "float": internalName.append("F"); break; case "double": internalName.append("D"); break; case "boolean": internalName.append("Z"); break; case "byte": internalName.append("B"); break; case "short": internalName.append("S"); break; case "char": internalName.append("C"); break; default: internalName.append('L').append(className.replace('.', '/')).append(';'); } return new WrappedType(Type.getType(internalName.toString()), isInterface); } public static WrappedType fromInternalName(String internalName, boolean isInterface) { if ("ZBCSIJFDV".contains(internalName) || internalName.startsWith("[")) { return new WrappedType(Type.getType(internalName), isInterface); } else { return new WrappedType(Type.getType("L" + internalName + ";"), isInterface); } } public static WrappedType from(Class clazz) { return new WrappedType(Type.getType(clazz), clazz.isInterface()); } public static WrappedType from(ClassNode classNode) { return new WrappedType(Type.getType("L" + classNode.name + ";"), (classNode.access & Opcodes.ACC_INTERFACE) != 0); } @Override public String toString() { return "WrappedType{" + "type=" + type + ", isInterface=" + isInterface + '}'; } @Override public boolean equals(Object other) { if (!(other instanceof WrappedType)) { return false; } return getType().equals(((WrappedType) other).getType()); } static class AbsentWrappedType extends WrappedType { private AbsentWrappedType() { super(null); } @Override public Type getType() { throw new UncompilableNodeException("Attempted to get type of AbsentWrappedType"); } @Override public boolean isInterface() { throw new UncompilableNodeException("Attempted to determine interface flag of AbsentWrappedType"); } @Override public int getSort() { throw new UncompilableNodeException("Attempted to get sort of AbsentWrappedType"); } @Override public boolean isPrimitive() { throw new UncompilableNodeException("Attempted to determine primitive flag of AbsentWrappedType"); } @Override public boolean isBoxed() { throw new UncompilableNodeException("Attempted to determine boxed flag of AbsentWrappedType"); } @Override public boolean isArray() { throw new UncompilableNodeException("Attempted to determine array flag of AbsentWrappedType"); } @Override public boolean isIntType() { throw new UncompilableNodeException("Attempted to determine isIntType flag of AbsentWrappedType"); } @Override public String unwrap() { throw new UncompilableNodeException("Attempted to unwrap AbsentWrappedType"); } @Override public String getInternalName() { throw new UncompilableNodeException("Attempted to get internal name of AbsentWrappedType"); } @Override public String getClassName() { throw new UncompilableNodeException("Attempted to get class name of AbsentWrappedType"); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/exceptions/UncompilableNodeException.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.exceptions; public class UncompilableNodeException extends RuntimeException { public UncompilableNodeException() { super(); } public UncompilableNodeException(String msg) { super(msg); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/IRExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.predefined.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; public abstract class IRExpression { private final WrappedType type; public IRExpression(WrappedType type) { this.type = type; } public WrappedType getType() { return type; } public abstract BytecodeBlock getInstructions(); public IRExpression arrayLength() { return new IRArrayLengthExpression(this); } public IRExpression getArrayElement(int index) { return new IRGetArrayElementExpression(this, IRExpressions.intConst(index)); } public IRExpression getArrayElement(IRExpression index) { return new IRGetArrayElementExpression(this, index); } public IRExpression setArrayElement(int index, IRExpression value) { return new IRSetArrayElementExpression(this, IRExpressions.intConst(index), value); } public IRExpression setArrayElement(IRExpression index, IRExpression value) { return new IRSetArrayElementExpression(this, index, value); } public IRExpression cast(ClassNode target) { return new IRCastExpression(this, WrappedType.from(target)); } public IRExpression cast(Class target) { return new IRCastExpression(this, WrappedType.from(target)); } public IRExpression cast(String target) { return new IRCastExpression(this, WrappedType.fromInternalName(target, false)); } public IRExpression cast(WrappedType type) { return new IRCastExpression(this, type); } public IRExpression instanceOf(ClassNode target) { return new IRInstanceOfExpression(this, WrappedType.from(target)); } public IRExpression instanceOf(Class target) { return new IRInstanceOfExpression(this, WrappedType.from(target)); } public IRExpression instanceOf(String target) { return new IRInstanceOfExpression(this, WrappedType.fromInternalName(target, false)); } public IRExpression instanceOf(WrappedType type) { return new IRInstanceOfExpression(this, type); } public IRExpression getField(String name, Class type) { return new IRGetFieldExpression(this, getType(), name, WrappedType.from(type)); } public IRExpression getField(String name, WrappedType type) { return new IRGetFieldExpression(this, getType(), name, type); } public IRExpression getField(FieldNode fieldNode) { return new IRGetFieldExpression(this, getType(), fieldNode.name, WrappedType.fromInternalName(fieldNode.desc, false)); } public IRExpression getField(Field field) { return new IRGetFieldExpression(this, getType(), field.getName(), WrappedType.from(field.getType())); } public IRExpression setField(String name, Class type, IRExpression value) { return new IRSetFieldExpression(this, value, getType(), name, WrappedType.from(type)); } public IRExpression setField(String name, WrappedType type, IRExpression value) { return new IRSetFieldExpression(this, value, getType(), name, type); } public IRExpression setField(FieldNode fieldNode, IRExpression value) { return new IRSetFieldExpression(this, value, getType(), fieldNode.name, WrappedType.fromInternalName(fieldNode.desc, false)); } public IRExpression setField(Field field, IRExpression value) { return new IRSetFieldExpression(this, value, getType(), field.getName(), WrappedType.from(field.getType())); } public IRExpression invoke(MethodNode methodNode, IRExpression... arguments) { return new IRInvocationExpression(this, getType(), methodNode.name, List.of(arguments), Utils.wrapMethodNodeParameters(methodNode), new WrappedType(Type.getReturnType(methodNode.desc))); } public IRExpression invoke(Method method, IRExpression... arguments) { return new IRInvocationExpression(this, getType(), method.getName(), List.of(arguments), Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } public IRExpression invoke(String name, List parameterTypes, WrappedType returnType, IRExpression... arguments) { return new IRInvocationExpression(this, getType(), name, List.of(arguments), parameterTypes, returnType); } public IRExpression ret() { return new IRReturnExpression(this); } public IRExpression throwMe() { return new IRThrowExceptionExpression(this); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/IRExpressions.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.flow.*; import xyz.itzsomebody.codegen.expressions.predefined.*; import xyz.itzsomebody.codegen.instructions.ConstantNode; import xyz.itzsomebody.codegen.instructions.SimpleNode; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class IRExpressions { // ARITHMETIC public static IRExpression intAdd(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_ADD, left, right); } public static IRExpression intSub(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_SUB, left, right); } public static IRExpression intMul(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_MUL, left, right); } public static IRExpression intDiv(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_DIV, left, right); } public static IRExpression intMod(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_MOD, left, right); } public static IRExpression intShiftLeft(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_SHIFT_LEFT, left, right); } public static IRExpression intShiftRight(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_SHIFT_RIGHT, left, right); } public static IRExpression intUnsignedShiftRight(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_UNSIGNED_SHIFT_RIGHT, left, right); } public static IRExpression intAnd(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_AND, left, right); } public static IRExpression intOr(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_OR, left, right); } public static IRExpression intXor(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.INT_XOR, left, right); } public static IRExpression longAdd(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_ADD, left, right); } public static IRExpression longSub(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_SUB, left, right); } public static IRExpression longMul(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_MUL, left, right); } public static IRExpression longDiv(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_DIV, left, right); } public static IRExpression longMod(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_MOD, left, right); } public static IRExpression longShiftLeft(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_SHIFT_LEFT, left, right); } public static IRExpression longShiftRight(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_SHIFT_RIGHT, left, right); } public static IRExpression longUnsignedShiftRight(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_UNSIGNED_SHIFT_RIGHT, left, right); } public static IRExpression longAnd(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_AND, left, right); } public static IRExpression longOr(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_OR, left, right); } public static IRExpression longXor(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.LONG_XOR, left, right); } public static IRExpression floatAdd(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.FLOAT_ADD, left, right); } public static IRExpression floatSub(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.FLOAT_SUB, left, right); } public static IRExpression floatMul(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.FLOAT_MUL, left, right); } public static IRExpression floatDiv(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.FLOAT_DIV, left, right); } public static IRExpression floatMod(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.FLOAT_MOD, left, right); } public static IRExpression doubleAdd(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.DOUBLE_ADD, left, right); } public static IRExpression doubleSub(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.DOUBLE_SUB, left, right); } public static IRExpression doubleMul(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.DOUBLE_MUL, left, right); } public static IRExpression doubleDiv(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.DOUBLE_DIV, left, right); } public static IRExpression doubleMod(IRExpression left, IRExpression right) { return new IRArithmeticExpression(SimpleNode.DOUBLE_MOD, left, right); } // ARRAYLENGTH public static IRExpression arrayLength(IRExpression array) { return new IRArrayLengthExpression(array); } // CAST public static IRExpression cast(IRExpression source, WrappedType targetType) { return new IRCastExpression(source, targetType); } // CONSTANT DYNAMIC public static IRExpression dynamicConst(String name, WrappedType type, WrappedHandle bootstrapMethod, List bootstrapArgs) { return new IRConstantExpression(ConstantNode.dynamicConst(name, type, bootstrapMethod, bootstrapArgs), type); } public static IRExpression dynamicConst(String name, WrappedType type, Method bootstrap, List bootstrapArgs) { return new IRConstantExpression(ConstantNode.dynamicConst(name, type, bootstrap, bootstrapArgs), type); } // CONSTANTS public static IRExpression nullConst(Class type) { return new IRConstantExpression(ConstantNode.nullConst(), WrappedType.from(type)); } public static IRExpression nullConst(ClassNode type) { return new IRConstantExpression(ConstantNode.nullConst(), WrappedType.from(type)); } public static IRExpression nullConst(WrappedType type) { return new IRConstantExpression(ConstantNode.nullConst(), type); } public static IRExpression booleanConst(boolean z) { return new IRConstantExpression(ConstantNode.booleanConst(z), WrappedType.from(boolean.class)); } public static IRExpression trueConst() { return booleanConst(true); } public static IRExpression falseConst() { return booleanConst(false); } public static IRExpression intConst(int i) { return new IRConstantExpression(ConstantNode.intConst(i), WrappedType.from(int.class)); } public static IRExpression longConst(long j) { return new IRConstantExpression(ConstantNode.longConst(j), WrappedType.from(long.class)); } public static IRExpression floatConst(float f) { return new IRConstantExpression(ConstantNode.floatConst(f), WrappedType.from(float.class)); } public static IRExpression doubleConst(double d) { return new IRConstantExpression(ConstantNode.doubleConst(d), WrappedType.from(double.class)); } public static IRExpression stringConst(String str) { return new IRConstantExpression(ConstantNode.stringConst(str), WrappedType.from(String.class)); } public static IRExpression classConst(Class clazz) { return new IRConstantExpression(ConstantNode.classConst(WrappedType.from(clazz)), WrappedType.from(Class.class)); } public static IRExpression classConst(WrappedType type) { return new IRConstantExpression(ConstantNode.classConst(type), WrappedType.from(Class.class)); } // GET ARRAY ELEMENT public static IRExpression getArrayElement(IRExpression array, int index) { return new IRGetArrayElementExpression(array, intConst(index)); } public static IRExpression getArrayElement(IRExpression array, IRExpression index) { return new IRGetArrayElementExpression(array, index); } // GET FIELD public static IRExpression getField(IRExpression instance, Field field) { return new IRGetFieldExpression(instance, field); } public static IRExpression getField(IRExpression instance, Class owner, String name, Class type) { return new IRGetFieldExpression(instance, WrappedType.from(owner), name, WrappedType.from(type)); } public static IRExpression getField(IRExpression instance, WrappedType owner, String name, WrappedType type) { return new IRGetFieldExpression(instance, owner, name, type); } public static IRExpression getStatic(Field field) { return new IRGetFieldExpression(null, field); } public static IRExpression getStatic(Class owner, String name, Class type) { return new IRGetFieldExpression(null, WrappedType.from(owner), name, WrappedType.from(type)); } public static IRExpression getStatic(WrappedType owner, String name, WrappedType type) { return new IRGetFieldExpression(null, owner, name, type); } // INSTANCE OF public static IRExpression instanceOf(IRExpression instance, Class type) { return new IRInstanceOfExpression(instance, WrappedType.from(type)); } public static IRExpression instanceOf(IRExpression instance, WrappedType type) { return new IRInstanceOfExpression(instance, type); } // INVOCATIONS public static IRExpression invokeVirtual(IRExpression instance, Method method, IRExpression... args) { return new IRInvocationExpression(instance, method, List.of(args)); } public static IRExpression invokeVirtual(IRExpression instance, MethodNode methodNode, IRExpression... arguments) { return new IRInvocationExpression(instance, instance.getType(), methodNode.name, List.of(arguments), Utils.wrapMethodNodeParameters(methodNode), new WrappedType(Type.getReturnType(methodNode.desc))); } public static IRExpression invokeVirtual(IRExpression instance, String name, List parameterTypes, WrappedType returnType, IRExpression... arguments) { return new IRInvocationExpression(instance, instance.getType(), name, List.of(arguments), parameterTypes, returnType); } public static IRExpression invokeVirtual(IRExpression instance, WrappedType owner, String name, List args, List argTypes, WrappedType returnType) { return new IRInvocationExpression(instance, owner, name, args, argTypes, returnType); } public static IRExpression invokeStatic(Method method, IRExpression... args) { return new IRInvocationExpression(null, method, List.of(args)); } public static IRExpression invokeStatic(ClassNode owner, MethodNode methodNode, IRExpression... arguments) { return new IRInvocationExpression(null, WrappedType.from(owner), methodNode.name, List.of(arguments), Utils.wrapMethodNodeParameters(methodNode), new WrappedType(Type.getReturnType(methodNode.desc))); } public static IRExpression invokeStatic(String owner, String name, List parameterTypes, WrappedType returnType, IRExpression... arguments) { return new IRInvocationExpression(null, WrappedType.fromInternalName(owner, false), name, List.of(arguments), parameterTypes, returnType); } public static IRExpression invokeStatic(WrappedType owner, String name, List args, List argTypes, WrappedType returnType) { return new IRInvocationExpression(null, owner, name, args, argTypes, returnType); } // INVOKE DYNAMIC public static IRExpression invokeDynamic(String name, List args, List argTypes, WrappedType returnType, Method bootstrap, List bootstrapArgs) { return new IRInvokeDynamicExpression(name, args, argTypes, returnType, WrappedHandle.getInvokeStaticHandle(bootstrap), bootstrapArgs); } public static IRExpression invokeDynamic(String name, List args, List argTypes, WrappedType returnType, WrappedHandle bootstrap, List bootstrapArgs) { return new IRInvokeDynamicExpression(name, args, argTypes, returnType, bootstrap, bootstrapArgs); } // NEGATIONS public static IRExpression negate(IRExpression operand) { return new IRNegateExpression(operand); } // NEW ARRAY public static IRExpression newArray(Class type, IRExpression... elements) { return new IRNewArrayExpression(intConst(elements.length), WrappedType.from(type), elements); } public static IRExpression newArray(WrappedType type, IRExpression... elements) { return new IRNewArrayExpression(intConst(elements.length), type, elements); } public static IRExpression newArray(int length, Class type, IRExpression... elements) { return new IRNewArrayExpression(intConst(length), WrappedType.from(type), elements); } public static IRExpression newArray(int length, WrappedType type, IRExpression... elements) { return new IRNewArrayExpression(intConst(length), type, elements); } public static IRExpression newArray(IRExpression length, Class type, IRExpression... elements) { return new IRNewArrayExpression(length, WrappedType.from(type), elements); } public static IRExpression newArray(IRExpression length, WrappedType type, IRExpression... elements) { return new IRNewArrayExpression(length, type, elements); } // NEW INSTANCE (CONSTRUCTOR INVOCATIONS) public static IRExpression newInstance(Constructor constructor, IRExpression... args) { return new IRNewInstanceExpression(WrappedType.from(constructor.getDeclaringClass()), Utils.wrapConstructorParameters(constructor), List.of(args)); } public static IRExpression newInstance(WrappedType type, List argumentTypes, List arguments) { return new IRNewInstanceExpression(type, argumentTypes, arguments); } // RETURNS public static IRExpression returnMe(IRExpression operand) { return new IRReturnExpression(operand); } // SET ARRAY ELEMENT public static IRExpression setArrayElement(IRExpression array, int index, IRExpression value) { return new IRSetArrayElementExpression(array, intConst(index), value); } public static IRExpression setArrayElement(IRExpression array, IRExpression index, IRExpression value) { return new IRSetArrayElementExpression(array, index, value); } // SET FIELD public static IRExpression setField(IRExpression instance, Field field, IRExpression value) { return new IRSetFieldExpression(instance, value, field); } public static IRExpression setField(IRExpression instance, Class owner, String name, Class type, IRExpression value) { return new IRSetFieldExpression(instance, value, WrappedType.from(owner), name, WrappedType.from(type)); } public static IRExpression setField(IRExpression instance, WrappedType owner, String name, WrappedType type, IRExpression value) { return new IRSetFieldExpression(instance, value, owner, name, type); } public static IRExpression setStatic(Field field, IRExpression value) { return new IRSetFieldExpression(null, value, field); } public static IRExpression setStatic(Class owner, String name, Class type, IRExpression value) { return new IRSetFieldExpression(null, value, WrappedType.from(owner), name, WrappedType.from(type)); } public static IRExpression setStatic(WrappedType owner, String name, WrappedType type, IRExpression value) { return new IRSetFieldExpression(null, value, owner, name, type); } public static IRExpression throwException(IRExpression exception) { return new IRThrowExceptionExpression(exception); } // FLOW STRUCTURES public static IRFlowStructure forLoop(BytecodeBlock initializer, BytecodeBlock condition, BytecodeBlock updater, BytecodeBlock body) { return new IRForStructure(initializer, condition, updater, body); } public static IRFlowStructure ifBlock(BytecodeBlock condition, BytecodeBlock ifTrue, BytecodeBlock ifFalse) { return new IRIfStructure(condition, ifTrue, ifFalse); } public static IRFlowStructure switchStatement(IRExpression operand, ArrayList keys, ArrayList cases, BytecodeBlock defaultBody) { return new IRSwitchStructure(operand, keys, cases, defaultBody); } public static IRFlowStructure synchronizedBlock(IRExpression instance, BytecodeBlock body) { return new IRSynchronizedStructure(instance, body); } public static IRFlowStructure tryCatch(BytecodeBlock tryBody, BytecodeBlock catchBody, WrappedType exceptionType) { return new IRTryCatchStructure(tryBody, catchBody, exceptionType); } public static IRFlowStructure whileLoop(BytecodeBlock condition, BytecodeBlock body) { return new IRWhileStructure(condition, body); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/IRVariable.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.predefined.IRSetVariableExpression; import xyz.itzsomebody.codegen.instructions.RegisterNode; public class IRVariable extends IRExpression { private final WrappedType wrappedType; private final int slot; public IRVariable(WrappedType wrappedType, int slot) { super(wrappedType); this.wrappedType = wrappedType; this.slot = slot; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock().append(RegisterNode.loadVar(this)); } public WrappedType getWrappedType() { return wrappedType; } public int getSlot() { return slot; } public IRExpression set(IRExpression expression) { return new IRSetVariableExpression(this, expression); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRFlowStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; public abstract class IRFlowStructure extends IRExpression { public IRFlowStructure() { super(WrappedType.getAbsent()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRForStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.instructions.BytecodeLabel; import xyz.itzsomebody.codegen.instructions.JumpNode; public class IRForStructure extends IRFlowStructure { private final BytecodeBlock initializer; private final BytecodeBlock condition; private final BytecodeBlock updater; private final BytecodeBlock body; private final BytecodeLabel continueLabel = new BytecodeLabel(); private final BytecodeLabel exitLabel = new BytecodeLabel(); public IRForStructure(BytecodeBlock initializer, BytecodeBlock condition, BytecodeBlock updater, BytecodeBlock body) { this.initializer = initializer; this.condition = condition; this.updater = updater; this.body = body; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() // Initializer .append(initializer) // Condition .append(continueLabel) .append(condition) .append(JumpNode.jumpIfZero(exitLabel)) // Exit if false // Updater .append(updater) // Body .append(body) .append(JumpNode.jumpUnconditionally(continueLabel)) // Next iteration .append(exitLabel); } public BytecodeLabel getContinueLabel() { return continueLabel; } public BytecodeLabel getExitLabel() { return exitLabel; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRIfStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.instructions.BytecodeLabel; import xyz.itzsomebody.codegen.instructions.JumpNode; public class IRIfStructure extends IRFlowStructure { private final BytecodeBlock condition; private final BytecodeBlock ifTrue; private final BytecodeBlock ifFalse; private final BytecodeLabel trueLabel = new BytecodeLabel(); private final BytecodeLabel exitLabel = new BytecodeLabel(); public IRIfStructure(BytecodeBlock condition, BytecodeBlock ifTrue, BytecodeBlock ifFalse) { this.condition = condition; this.ifTrue = ifTrue; this.ifFalse = ifFalse; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() // Condition .append(condition) .append(JumpNode.jumpIfNotZero(trueLabel)) // Execute this if false .append(ifFalse) .append(JumpNode.jumpUnconditionally(exitLabel)) // Don't execute the ifTrue block // Execute this if true .append(trueLabel) .append(ifTrue) // Exit .append(exitLabel); } public BytecodeLabel getTrueLabel() { return trueLabel; } public BytecodeLabel getExitLabel() { return exitLabel; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRSwitchStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import org.jetbrains.annotations.NotNull; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.BytecodeLabel; import xyz.itzsomebody.codegen.instructions.JumpNode; import xyz.itzsomebody.codegen.instructions.SwitchNode; import java.util.ArrayList; import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.IntStream; public class IRSwitchStructure extends IRFlowStructure { private final IRExpression operand; private final SortedSet cases = new TreeSet<>(); private final BytecodeBlock defaultBody; private final ArrayList caseLabels = new ArrayList<>(); private final BytecodeLabel defaultLabel = new BytecodeLabel(); private final BytecodeLabel exitLabel = new BytecodeLabel(); public IRSwitchStructure(IRExpression operand, ArrayList keys, ArrayList caseBodies, BytecodeBlock defaultBody) { this.operand = operand; this.defaultBody = defaultBody; IntStream.range(0, keys.size()).forEach(index -> cases.add(new IRCaseStructure(keys.get(index), caseBodies.get(index)))); } @Override public BytecodeBlock getInstructions() { var block = new BytecodeBlock() .append(operand.getInstructions()) .append(new SwitchNode(cases.stream().map(IRCaseStructure::getKey).collect(Collectors.toList()), caseLabels, defaultLabel)); // Cases cases.forEach(caseStructure -> { var caseLabel = new BytecodeLabel(); block.append(caseLabel) .append(caseStructure.getBody()) .append(JumpNode.jumpUnconditionally(exitLabel)); caseLabels.add(caseLabel); }); // Default block.append(defaultLabel) .append(defaultBody); // Exit block.append(exitLabel); return block; } public ArrayList getCaseLabels() { return caseLabels; } public BytecodeLabel getDefaultLabel() { return defaultLabel; } public BytecodeLabel getExitLabel() { return exitLabel; } static class IRCaseStructure implements Comparable { private final int key; private final BytecodeBlock body; IRCaseStructure(int key, BytecodeBlock body) { this.key = key; this.body = body; } public int getKey() { return key; } public BytecodeBlock getBody() { return body; } @Override public int compareTo(@NotNull IRSwitchStructure.IRCaseStructure other) { return Integer.compare(key, other.key); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRSynchronizedStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRSynchronizedStructure extends IRFlowStructure { private final IRExpression instance; private final BytecodeBlock body; public IRSynchronizedStructure(IRExpression instance, BytecodeBlock body) { this.instance = instance; this.body = body; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(instance.getInstructions()) .append(SimpleNode.ENTER_MONITOR) .append(body) .append(instance.getInstructions()) .append(SimpleNode.EXIT_MONITOR); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRTryCatchStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import org.objectweb.asm.tree.TryCatchBlockNode; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.instructions.BytecodeLabel; import xyz.itzsomebody.codegen.instructions.JumpNode; public class IRTryCatchStructure extends IRFlowStructure { private final BytecodeBlock trapRange; private final BytecodeBlock handler; private final WrappedType exceptionType; private final BytecodeLabel trapStartLabel = new BytecodeLabel(); private final BytecodeLabel trapEndLabel = new BytecodeLabel(); private final BytecodeLabel handlerLabel = new BytecodeLabel(); private final BytecodeLabel exitLabel = new BytecodeLabel(); public IRTryCatchStructure(BytecodeBlock trapRange, BytecodeBlock handler, WrappedType exceptionType) { this.trapRange = trapRange; this.handler = handler; this.exceptionType = exceptionType; } public TryCatchBlockNode getTryCatchBlocKNode() { return new TryCatchBlockNode(trapStartLabel.getLabel(), trapEndLabel.getLabel(), handlerLabel.getLabel(), exceptionType.getInternalName()); } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() // Try block .append(trapStartLabel) .append(trapRange) .append(trapEndLabel) .append(JumpNode.jumpUnconditionally(exitLabel)) // No exception has been thrown so skip the handler // Catch block .append(handlerLabel) .append(handler) // Exit .append(exitLabel); } public BytecodeLabel getTrapStartLabel() { return trapStartLabel; } public BytecodeLabel getTrapEndLabel() { return trapEndLabel; } public BytecodeLabel getHandlerLabel() { return handlerLabel; } public BytecodeLabel getExitLabel() { return exitLabel; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/flow/IRWhileStructure.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.flow; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.instructions.BytecodeLabel; import xyz.itzsomebody.codegen.instructions.JumpNode; public class IRWhileStructure extends IRFlowStructure { private final BytecodeBlock condition; private final BytecodeBlock body; private final BytecodeLabel continueLabel = new BytecodeLabel(); private final BytecodeLabel exitLabel = new BytecodeLabel(); public IRWhileStructure(BytecodeBlock condition, BytecodeBlock body) { this.condition = condition; this.body = body; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() // Condition .append(continueLabel) .append(condition) .append(JumpNode.jumpIfZero(exitLabel)) // Exit if false // Body .append(body) .append(JumpNode.jumpUnconditionally(continueLabel)) // Next iteration // Exit .append(exitLabel); } public BytecodeLabel getContinueLabel() { return continueLabel; } public BytecodeLabel getExitLabel() { return exitLabel; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRArithmeticExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRArithmeticExpression extends IRExpression { private final SimpleNode operation; private final IRExpression left; private final IRExpression right; public IRArithmeticExpression(SimpleNode operation, IRExpression left, IRExpression right) { super(left.getType()); // Left expression should ALWAYS be the resultant type (i.e. LSHL/LSHR/LUSHR) this.operation = operation; this.left = left; this.right = right; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(left.getInstructions()) .append(right.getInstructions()) .append(operation); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRArrayLengthExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRArrayLengthExpression extends IRExpression { private final IRExpression array; public IRArrayLengthExpression(IRExpression array) { super(WrappedType.from(int.class)); this.array = array; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(array.getInstructions()) .append(SimpleNode.ARRAY_LENGTH); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRCastExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.objectweb.asm.Type; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.InvokeNode; import xyz.itzsomebody.codegen.instructions.SimpleNode; import xyz.itzsomebody.codegen.instructions.TypeNode; import java.util.Collections; import java.util.List; public class IRCastExpression extends IRExpression { private final IRExpression castMe; public IRCastExpression(IRExpression castMe, WrappedType castType) { super(castType); this.castMe = castMe; } @Override public BytecodeBlock getInstructions() { var block = new BytecodeBlock().append(castMe.getInstructions()); var currentType = castMe.getType(); var targetType = getType(); if (currentType.equals(targetType)) { return block; } if (currentType.isPrimitive()) { if (targetType.isPrimitive()) { castPrimitives(block, currentType, targetType); } else if (targetType.isBoxed()) { block.append(InvokeNode.invokeStatic(targetType, "valueOf", List.of(currentType), targetType)); } else { block.append(InvokeNode.invokeStatic(Utils.box(currentType), "valueOf", List.of(currentType), Utils.box(currentType))) .append(TypeNode.cast(targetType)); } } else if (currentType.isBoxed()) { if (targetType.isPrimitive()) { var primitiveType = currentType.getPrimitiveType(); block.append(InvokeNode.invokeVirtual(currentType, primitiveType.getClassName() + "Value", Collections.emptyList(), primitiveType)); castPrimitives(block, primitiveType, targetType); } else { block.append(TypeNode.cast(targetType)); } } else { if (targetType.isPrimitive()) { var primitiveType = targetType.getPrimitiveType(); block.append(TypeNode.cast(Utils.box(targetType))) .append(InvokeNode.invokeVirtual(targetType, primitiveType.getClassName() + "Value", Collections.emptyList(), primitiveType)); } else { block.append(TypeNode.cast(targetType)); } } return block; } @SuppressWarnings("Duplicates") private static void castPrimitives(BytecodeBlock block, WrappedType source, WrappedType target) { var sourceSort = source.getSort(); var targetSort = target.getSort(); if (sourceSort == targetSort) { return; // Casting primitive to same primitive type = redundant } if (sourceSort == Type.BOOLEAN || sourceSort == Type.BYTE) { if (target.isIntType()) { return; } if (targetSort == Type.FLOAT) { block.append(SimpleNode.CAST_INT_TO_FLOAT); return; } else if (targetSort == Type.LONG) { block.append(SimpleNode.CAST_INT_TO_LONG); return; } else if (targetSort == Type.DOUBLE) { block.append(SimpleNode.CAST_INT_TO_DOUBLE); return; } } else if (sourceSort == Type.CHAR) { if (targetSort == Type.BYTE) { block.append(SimpleNode.CAST_INT_TO_BYTE); return; } if (target.isIntType()) { // Non-byte integer return; } if (targetSort == Type.FLOAT) { block.append(SimpleNode.CAST_INT_TO_FLOAT); return; } else if (targetSort == Type.LONG) { block.append(SimpleNode.CAST_INT_TO_LONG); return; } else if (targetSort == Type.DOUBLE) { block.append(SimpleNode.CAST_INT_TO_DOUBLE); return; } } else if (sourceSort == Type.SHORT) { if (targetSort == Type.BYTE) { block.append(SimpleNode.CAST_INT_TO_BYTE); return; } if (targetSort == Type.CHAR) { block.append(SimpleNode.CAST_INT_TO_CHAR); return; } if (target.isIntType()) { // Non-byte integer return; } if (targetSort == Type.FLOAT) { block.append(SimpleNode.CAST_INT_TO_FLOAT); return; } else if (targetSort == Type.LONG) { block.append(SimpleNode.CAST_INT_TO_LONG); return; } else if (targetSort == Type.DOUBLE) { block.append(SimpleNode.CAST_INT_TO_DOUBLE); return; } } else if (sourceSort == Type.INT) { if (targetSort == Type.BYTE) { block.append(SimpleNode.CAST_INT_TO_BYTE); return; } else if (targetSort == Type.CHAR) { block.append(SimpleNode.CAST_INT_TO_CHAR); return; } else if (targetSort == Type.SHORT) { block.append(SimpleNode.CAST_INT_TO_SHORT); return; } else if (targetSort == Type.FLOAT) { block.append(SimpleNode.CAST_INT_TO_FLOAT); return; } else if (targetSort == Type.LONG) { block.append(SimpleNode.CAST_INT_TO_LONG); return; } else if (targetSort == Type.DOUBLE) { block.append(SimpleNode.CAST_INT_TO_DOUBLE); return; } } else if (sourceSort == Type.LONG) { if (target.isIntType()) { block.append(SimpleNode.CAST_LONG_TO_INT); if (targetSort == Type.BYTE) { block.append(SimpleNode.CAST_INT_TO_BYTE); } else if (targetSort == Type.CHAR) { block.append(SimpleNode.CAST_INT_TO_CHAR); } else if (targetSort == Type.SHORT) { block.append(SimpleNode.CAST_INT_TO_SHORT); } return; } else if (targetSort == Type.FLOAT) { block.append(SimpleNode.CAST_LONG_TO_FLOAT); return; } else if (targetSort == Type.DOUBLE) { block.append(SimpleNode.CAST_LONG_TO_DOUBLE); return; } } else if (sourceSort == Type.FLOAT) { if (target.isIntType()) { block.append(SimpleNode.CAST_FLOAT_TO_INT); if (targetSort == Type.BYTE) { block.append(SimpleNode.CAST_INT_TO_BYTE); } else if (targetSort == Type.CHAR) { block.append(SimpleNode.CAST_INT_TO_CHAR); } else if (targetSort == Type.SHORT) { block.append(SimpleNode.CAST_INT_TO_SHORT); } return; } else if (targetSort == Type.LONG) { block.append(SimpleNode.CAST_FLOAT_TO_LONG); return; } else if (targetSort == Type.DOUBLE) { block.append(SimpleNode.CAST_FLOAT_TO_DOUBLE); return; } } else if (sourceSort == Type.DOUBLE) { if (target.isIntType()) { block.append(SimpleNode.CAST_DOUBLE_TO_INT); if (targetSort == Type.BYTE) { block.append(SimpleNode.CAST_INT_TO_BYTE); } else if (targetSort == Type.CHAR) { block.append(SimpleNode.CAST_INT_TO_CHAR); } else if (targetSort == Type.SHORT) { block.append(SimpleNode.CAST_INT_TO_SHORT); } return; } else if (targetSort == Type.FLOAT) { block.append(SimpleNode.CAST_DOUBLE_TO_FLOAT); return; } else if (targetSort == Type.LONG) { block.append(SimpleNode.CAST_DOUBLE_TO_LONG); return; } } throw new UncompilableNodeException("Cannot cast " + source + " to " + target); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRConstantExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.ConstantNode; public class IRConstantExpression extends IRExpression { private final ConstantNode cst; public IRConstantExpression(ConstantNode cst, WrappedType type) { super(type); this.cst = cst; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock().append(cst); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRGetArrayElementExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRGetArrayElementExpression extends IRExpression { private final IRExpression array; private final IRExpression index; public IRGetArrayElementExpression(IRExpression array, IRExpression index) { super(array.getType()); this.array = array; this.index = index; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(array.getInstructions()) .append(index.getInstructions()) .append(SimpleNode.getArrayLoadOp(getType())); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRGetFieldExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.FieldAccessNode; import java.lang.reflect.Field; public class IRGetFieldExpression extends IRExpression { private final IRExpression instance; private final WrappedType owner; private final String name; public IRGetFieldExpression(IRExpression instance, WrappedType owner, String name, WrappedType type) { super(type); this.instance = instance; this.owner = owner; this.name = name; } public IRGetFieldExpression(IRExpression instance, Field field) { this(instance, WrappedType.from(field.getDeclaringClass()), field.getName(), WrappedType.from(field.getType())); } @Override public BytecodeBlock getInstructions() { if (instance == null) { return new BytecodeBlock().append(FieldAccessNode.getStatic(owner, name, getType())); } else { return new BytecodeBlock() .append(instance.getInstructions()) .append(FieldAccessNode.getField(owner, name, getType())); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRInstanceOfExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.TypeNode; public class IRInstanceOfExpression extends IRExpression { private final IRExpression instance; private final WrappedType type; public IRInstanceOfExpression(IRExpression instance, WrappedType type) { super(WrappedType.from(boolean.class)); this.instance = instance; this.type = type; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(instance.getInstructions()) .append(TypeNode.instanceOf(type)); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRInvocationExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.InvokeNode; import java.lang.reflect.Method; import java.util.List; public class IRInvocationExpression extends IRExpression { private final IRExpression instance; private final WrappedType owner; private final String name; private final List args; private final List argTypes; public IRInvocationExpression(IRExpression instance, WrappedType owner, String name, List args, List argTypes, WrappedType returnType) { super(returnType); this.instance = instance; this.owner = owner; this.name = name; this.args = args; this.argTypes = argTypes; } public IRInvocationExpression(IRExpression instance, Method method, List args) { this(instance, WrappedType.from(method.getDeclaringClass()), method.getName(), args, Utils.wrapMethodParameters(method), WrappedType.from(method.getReturnType())); } @Override public BytecodeBlock getInstructions() { var block = new BytecodeBlock(); if (instance != null) { block.append(instance.getInstructions()); } args.forEach(arg -> block.append(arg.getInstructions())); if (instance == null) { block.append(InvokeNode.invokeStatic(owner, name, argTypes, getType())); } else if (owner.isInterface()) { block.append(InvokeNode.invokeInterface(owner, name, argTypes, getType())); } else { block.append(InvokeNode.invokeVirtual(owner, name, argTypes, getType())); } return block; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRInvokeDynamicExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.ConstantNode; import xyz.itzsomebody.codegen.instructions.InvokeDynamicNode; import java.util.List; public class IRInvokeDynamicExpression extends IRExpression { private final String name; private final List args; private final List argTypes; private final WrappedHandle bootstrap; private final List bootstrapArgs; public IRInvokeDynamicExpression(String name, List args, List argTypes, WrappedType returnType, WrappedHandle bootstrap, List bootstrapArgs) { super(returnType); this.name = name; this.args = args; this.argTypes = argTypes; this.bootstrap = bootstrap; this.bootstrapArgs = bootstrapArgs; } @Override public BytecodeBlock getInstructions() { var block = new BytecodeBlock(); args.forEach(arg -> block.append(arg.getInstructions())); block.append(InvokeDynamicNode.invokeDynamic(name, argTypes, getType(), bootstrap, bootstrapArgs)); return block; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRNegateExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRNegateExpression extends IRExpression { private final IRExpression operand; public IRNegateExpression(IRExpression operand) { super(operand.getType()); this.operand = operand; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(operand.getInstructions()) .append(SimpleNode.negateOpcodeFor(operand.getType())); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRNewArrayExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.ConstantNode; import xyz.itzsomebody.codegen.instructions.NewArrayNode; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRNewArrayExpression extends IRExpression { private final IRExpression length; private final WrappedType type; private final IRExpression[] elements; public IRNewArrayExpression(IRExpression length, WrappedType type, IRExpression[] elements) { super(type); this.length = length; this.type = type; this.elements = elements; } @Override public BytecodeBlock getInstructions() { BytecodeBlock block = new BytecodeBlock() .append(length.getInstructions()) .append(new NewArrayNode(type)); for (int i = 0; i < elements.length; i++) { IRExpression element = elements[i]; block.append(SimpleNode.DUP) .append(ConstantNode.intConst(i)) .append(element.getInstructions()) .append(SimpleNode.getArrayStoreOp(type)); } return block; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRNewInstanceExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.InvokeNode; import xyz.itzsomebody.codegen.instructions.SimpleNode; import xyz.itzsomebody.codegen.instructions.TypeNode; import java.util.List; public class IRNewInstanceExpression extends IRExpression { private final List argumentTypes; private final List arguments; public IRNewInstanceExpression(WrappedType type, List argumentTypes, List arguments) { super(type); this.argumentTypes = argumentTypes; this.arguments = arguments; } @Override public BytecodeBlock getInstructions() { var block = new BytecodeBlock() .append(TypeNode.newInstance(getType())) .append(SimpleNode.DUP); for (var expr : arguments) { block.append(expr.getInstructions()); } block.append(InvokeNode.invokeConstructor(getType(), argumentTypes)); return block; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRReturnExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.objectweb.asm.Type; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRReturnExpression extends IRExpression { private final IRExpression target; public IRReturnExpression(IRExpression target) { super(WrappedType.getAbsent()); this.target = target; } @Override public BytecodeBlock getInstructions() { if (target == null) { return new BytecodeBlock().append(SimpleNode.RETURN_VOID); } var block = new BytecodeBlock().append(target.getInstructions()); var type = target.getType(); switch (type.getSort()) { case Type.VOID: block.append(SimpleNode.RETURN_VOID); break; case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: block.append(SimpleNode.RETURN_INT); break; case Type.FLOAT: block.append(SimpleNode.RETURN_FLOAT); break; case Type.LONG: block.append(SimpleNode.RETURN_LONG); break; case Type.DOUBLE: block.append(SimpleNode.RETURN_DOUBLE); break; default: block.append(SimpleNode.RETURN_OBJECT); } return block; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRSetArrayElementExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRSetArrayElementExpression extends IRExpression { private final IRExpression array; private final IRExpression index; private final IRExpression value; public IRSetArrayElementExpression(IRExpression array, IRExpression index, IRExpression value) { super(WrappedType.getAbsent()); this.array = array; this.index = index; this.value = value; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(array.getInstructions()) .append(index.getInstructions()) .append(value.getInstructions()) .append(SimpleNode.getArrayStoreOp(array.getType())); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRSetFieldExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.FieldAccessNode; import java.lang.reflect.Field; public class IRSetFieldExpression extends IRExpression { private final IRExpression instance; private final IRExpression value; private final WrappedType owner; private final String name; public IRSetFieldExpression(IRExpression instance, IRExpression value, WrappedType owner, String name, WrappedType type) { super(type); this.instance = instance; this.value = value; this.owner = owner; this.name = name; } public IRSetFieldExpression(IRExpression instance, IRExpression value, Field field) { this(instance, value, WrappedType.from(field.getDeclaringClass()), field.getName(), WrappedType.from(field.getType())); } @Override public BytecodeBlock getInstructions() { if (instance == null) { return new BytecodeBlock() .append(value.getInstructions()) .append(FieldAccessNode.putStatic(owner, name, getType())); } else { return new BytecodeBlock() .append(instance.getInstructions()) .append(value.getInstructions()) .append(FieldAccessNode.putField(owner, name, getType())); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRSetVariableExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.expressions.IRVariable; import xyz.itzsomebody.codegen.instructions.RegisterNode; public class IRSetVariableExpression extends IRExpression { private final IRVariable variable; private final IRExpression expression; public IRSetVariableExpression(IRVariable variable, IRExpression expression) { super(WrappedType.getAbsent()); this.variable = variable; this.expression = expression; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(expression.getInstructions()) .append(RegisterNode.storeVar(variable)); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/expressions/predefined/IRThrowExceptionExpression.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.instructions.SimpleNode; public class IRThrowExceptionExpression extends IRExpression { private final IRExpression exception; public IRThrowExceptionExpression(IRExpression exception) { super(WrappedType.getAbsent()); this.exception = exception; } @Override public BytecodeBlock getInstructions() { return new BytecodeBlock() .append(exception.getInstructions()) .append(SimpleNode.THROW_EXCEPTION); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/BytecodeLabel.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.LabelNode; public class BytecodeLabel implements CompilableNode { private final LabelNode label; public BytecodeLabel() { this.label = new LabelNode(); } public BytecodeLabel(LabelNode label) { this.label = label; } @Override public AbstractInsnNode getNode() { return label; } public LabelNode getLabel() { return label; } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/CompilableNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.tree.AbstractInsnNode; public interface CompilableNode { AbstractInsnNode getNode(); } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/ConstantNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.ConstantDynamic; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; import java.lang.reflect.Method; import java.util.List; public abstract class ConstantNode implements CompilableNode { // todo: constants of type Handle public abstract Object getValue(); public static ConstantNode nullConst() { return new NullConst(); } public static ConstantNode booleanConst(boolean z) { return new BooleanConst(z); } public static ConstantNode intConst(int i) { return new IntConst(i); } public static ConstantNode floatConst(float f) { return new FloatConst(f); } public static ConstantNode longConst(long j) { return new LongConst(j); } public static ConstantNode doubleConst(double d) { return new DoubleConst(d); } public static ConstantNode stringConst(String s) { return new StringConst(s); } public static ConstantNode classConst(WrappedType type) { return new ClassConst(type); } public static ConstantNode dynamicConst(String name, WrappedType type, WrappedHandle bootstrapMethod, List bootstrapArgs) { return new DynamicConst(name, type, bootstrapMethod, bootstrapArgs); } public static ConstantNode dynamicConst(String name, WrappedType type, Method bootstrap, List bootstrapArgs) { return dynamicConst(name, type, WrappedHandle.getInvokeStaticHandle(bootstrap), bootstrapArgs); } public static class NullConst extends ConstantNode { @Override public Object getValue() { return null; } @Override public AbstractInsnNode getNode() { return new InsnNode(Opcodes.ACONST_NULL); } } public static class BooleanConst extends ConstantNode { private final boolean value; public BooleanConst(boolean value) { this.value = value; } @Override public Boolean getValue() { return value; } @Override public AbstractInsnNode getNode() { if (value) { return new InsnNode(Opcodes.ICONST_1); } else { return new InsnNode(Opcodes.ICONST_0); } } } public static class IntConst extends ConstantNode { private final int value; public IntConst(int value) { this.value = value; } @Override public Integer getValue() { return value; } @Override public AbstractInsnNode getNode() { if (value >= -1 && value <= 5) { return new InsnNode(value + 3); } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { return new IntInsnNode(Opcodes.BIPUSH, value); } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { return new IntInsnNode(Opcodes.SIPUSH, value); } else { return new LdcInsnNode(value); } } } public static class FloatConst extends ConstantNode { private final float value; public FloatConst(float value) { this.value = value; } @Override public Float getValue() { return value; } @Override public AbstractInsnNode getNode() { if (value == 0F || value == 1F || value == 2F) { return new InsnNode((int) value + 11); } else { return new LdcInsnNode(value); } } } public static class LongConst extends ConstantNode { private final long value; public LongConst(long value) { this.value = value; } @Override public Long getValue() { return value; } @Override public AbstractInsnNode getNode() { if (value == 0L || value == 1L) { return new InsnNode((int) value + 9); } else { return new LdcInsnNode(value); } } } public static class DoubleConst extends ConstantNode { private final double value; public DoubleConst(double value) { this.value = value; } @Override public Double getValue() { return value; } @Override public AbstractInsnNode getNode() { if (value == 0D || value == 1D) { return new InsnNode((int) value + 14); } else { return new LdcInsnNode(value); } } } public static class StringConst extends ConstantNode { private final String value; public StringConst(String value) { this.value = value; } @Override public String getValue() { return value; } @Override public AbstractInsnNode getNode() { return new LdcInsnNode(value); } } public static class ClassConst extends ConstantNode { private final WrappedType type; public ClassConst(WrappedType type) { this.type = type; } @Override public Object getValue() { return type; } @Override public AbstractInsnNode getNode() { return new LdcInsnNode(type.getType()); } } public static class DynamicConst extends ConstantNode { private final String name; private final WrappedType type; private final WrappedHandle bootstrapMethod; private final List bootstrapArgs; public DynamicConst(String name, WrappedType type, WrappedHandle bootstrapMethod, List bootstrapArgs) { this.name = name; this.type = type; this.bootstrapMethod = bootstrapMethod; this.bootstrapArgs = bootstrapArgs; } @Override public AbstractInsnNode getNode() { return new LdcInsnNode(new ConstantDynamic(name, type.unwrap(), bootstrapMethod.constructHandle(), Utils.unpackConstants(bootstrapArgs))); } @Override public Object getValue() { return new UncompilableNodeException("Attempted to get value of dynamic constant"); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/FieldAccessNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import xyz.itzsomebody.codegen.WrappedType; public class FieldAccessNode implements CompilableNode { private final int opcode; private final WrappedType owner; private final String name; private final WrappedType type; public FieldAccessNode(int opcode, WrappedType owner, String name, WrappedType type) { this.opcode = opcode; this.owner = owner; this.name = name; this.type = type; } @Override public AbstractInsnNode getNode() { return new FieldInsnNode(opcode, owner.getInternalName(), name, type.unwrap()); } public static FieldAccessNode getStatic(WrappedType owner, String name, WrappedType type) { return new FieldAccessNode(Opcodes.GETSTATIC, owner, name, type); } public static FieldAccessNode putStatic(WrappedType owner, String name, WrappedType type) { return new FieldAccessNode(Opcodes.PUTSTATIC, owner, name, type); } public static FieldAccessNode getField(WrappedType owner, String name, WrappedType type) { return new FieldAccessNode(Opcodes.GETFIELD, owner, name, type); } public static FieldAccessNode putField(WrappedType owner, String name, WrappedType type) { return new FieldAccessNode(Opcodes.PUTFIELD, owner, name, type); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/InvokeDynamicNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import java.lang.reflect.Method; import java.util.List; public class InvokeDynamicNode implements CompilableNode { private final String name; private final List parameterTypes; private final WrappedType returnType; private final WrappedHandle bootstrapMethod; private final List bootstrapArgs; public InvokeDynamicNode(String name, List parameterTypes, WrappedType returnType, WrappedHandle bootstrapMethod, List bootstrapArgs) { this.name = name; this.parameterTypes = parameterTypes; this.returnType = returnType; this.bootstrapMethod = bootstrapMethod; this.bootstrapArgs = bootstrapArgs; } @Override public AbstractInsnNode getNode() { return new InvokeDynamicInsnNode(name, Utils.unwrapMethodDescriptor(parameterTypes, returnType), bootstrapMethod.constructHandle(), Utils.unpackConstants(bootstrapArgs)); } public static InvokeDynamicNode invokeDynamic(String name, List parameterTypes, WrappedType returnType, WrappedHandle bootstrapMethod, List bootstrapArgs) { return new InvokeDynamicNode(name, parameterTypes, returnType, bootstrapMethod, bootstrapArgs); } public static InvokeDynamicNode invokeDynamic(String name, List parameterTypes, WrappedType returnType, Method bootstrap, List bootstrapArgs) { return invokeDynamic(name, parameterTypes, returnType, WrappedHandle.getInvokeStaticHandle(bootstrap), bootstrapArgs); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/InvokeNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import xyz.itzsomebody.codegen.Utils; import xyz.itzsomebody.codegen.WrappedType; import java.util.List; public class InvokeNode implements CompilableNode { private final int opcode; private final WrappedType owner; private final String name; private final List parameterTypes; private final WrappedType returnType; public InvokeNode(int opcode, WrappedType owner, String name, List parameterTypes, WrappedType returnType) { this.opcode = opcode; this.owner = owner; this.name = name; this.parameterTypes = parameterTypes; this.returnType = returnType; } @Override public AbstractInsnNode getNode() { return new MethodInsnNode(opcode, owner.getInternalName(), name, Utils.unwrapMethodDescriptor(parameterTypes, returnType), owner.isInterface()); } public static InvokeNode invokeStatic(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new InvokeNode(Opcodes.INVOKESTATIC, owner, name, parameterTypes, returnType); } public static InvokeNode invokeVirtual(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new InvokeNode(Opcodes.INVOKEVIRTUAL, owner, name, parameterTypes, returnType); } public static InvokeNode invokeInterface(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new InvokeNode(Opcodes.INVOKEINTERFACE, owner, name, parameterTypes, returnType); } public static InvokeNode invokeSpecial(WrappedType owner, String name, List parameterTypes, WrappedType returnType) { return new InvokeNode(Opcodes.INVOKESPECIAL, owner, name, parameterTypes, returnType); } public static InvokeNode invokeConstructor(WrappedType owner, List parameterTypes) { return new InvokeNode(Opcodes.INVOKESPECIAL, owner, "", parameterTypes, WrappedType.from(void.class)); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/JumpNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.JumpInsnNode; public class JumpNode implements CompilableNode { private final int opcode; private final BytecodeLabel target; public JumpNode(int opcode, BytecodeLabel target) { this.opcode = opcode; this.target = target; } @Override public AbstractInsnNode getNode() { return new JumpInsnNode(opcode, target.getLabel()); } public static JumpNode jumpIfZero(BytecodeLabel target) { return new JumpNode(Opcodes.IFEQ, target); } public static JumpNode jumpIfNotZero(BytecodeLabel target) { return new JumpNode(Opcodes.IFNE, target); } public static JumpNode jumpIfLessThanZero(BytecodeLabel target) { return new JumpNode(Opcodes.IFLT, target); } public static JumpNode jumpIfLessThanOrEqualToZero(BytecodeLabel target) { return new JumpNode(Opcodes.IFLE, target); } public static JumpNode jumpIfGreaterThanZero(BytecodeLabel target) { return new JumpNode(Opcodes.IFGT, target); } public static JumpNode jumpIfGreaterThanOrEqualToZero(BytecodeLabel target) { return new JumpNode(Opcodes.IFGE, target); } public static JumpNode jumpIfIntEqual(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ICMPEQ, target); } public static JumpNode jumpIfIntNotEqual(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ICMPNE, target); } public static JumpNode jumpIfIntLessThan(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ICMPLT, target); } public static JumpNode jumpIfIntLessThanOrEqualToZero(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ICMPLE, target); } public static JumpNode jumpIfIntGreaterThan(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ICMPGT, target); } public static JumpNode jumpIfIntGreaterThanOrEqualToZero(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ICMPGE, target); } public static JumpNode jumpIfObjectEqual(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ACMPEQ, target); } public static JumpNode jumpIfObjectNotEqual(BytecodeLabel target) { return new JumpNode(Opcodes.IF_ACMPNE, target); } public static JumpNode jumpUnconditionally(BytecodeLabel target) { return new JumpNode(Opcodes.GOTO, target); } public static JumpNode jsr(BytecodeLabel target) { return new JumpNode(Opcodes.JSR, target); } public static JumpNode jumpIfNull(BytecodeLabel target) { return new JumpNode(Opcodes.IFNULL, target); } public static JumpNode jumpIfNotNull(BytecodeLabel target) { return new JumpNode(Opcodes.IFNONNULL, target); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/NewArrayNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; public class NewArrayNode implements CompilableNode { private final WrappedType wrappedType; public NewArrayNode(WrappedType wrappedType) { this.wrappedType = wrappedType; } @Override public AbstractInsnNode getNode() { if (wrappedType.isPrimitive()) { return new IntInsnNode(Opcodes.NEWARRAY, wrappedType.getNewArraySort()); } else { return new TypeInsnNode(Opcodes.ANEWARRAY, wrappedType.getInternalName()); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/RegisterNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.VarInsnNode; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; import xyz.itzsomebody.codegen.expressions.IRVariable; public class RegisterNode implements CompilableNode { private final int opcode; private final int slot; public RegisterNode(int opcode, int slot) { this.opcode = opcode; this.slot = slot; } @Override public AbstractInsnNode getNode() { return new VarInsnNode(opcode, slot); } public static RegisterNode loadInt(int slot) { return new RegisterNode(Opcodes.ILOAD, slot); } public static RegisterNode loadLong(int slot) { return new RegisterNode(Opcodes.LLOAD, slot); } public static RegisterNode loadFloat(int slot) { return new RegisterNode(Opcodes.FLOAD, slot); } public static RegisterNode loadDouble(int slot) { return new RegisterNode(Opcodes.DLOAD, slot); } public static RegisterNode loadObject(int slot) { return new RegisterNode(Opcodes.ALOAD, slot); } public static RegisterNode storeInt(int slot) { return new RegisterNode(Opcodes.ISTORE, slot); } public static RegisterNode storeLong(int slot) { return new RegisterNode(Opcodes.LSTORE, slot); } public static RegisterNode storeFloat(int slot) { return new RegisterNode(Opcodes.FSTORE, slot); } public static RegisterNode storeDouble(int slot) { return new RegisterNode(Opcodes.DSTORE, slot); } public static RegisterNode storeObject(int slot) { return new RegisterNode(Opcodes.ASTORE, slot); } public static RegisterNode ret(int slot) { return new RegisterNode(Opcodes.RET, slot); } // todo: add jsr support to troll cooker public static RegisterNode loadVar(IRVariable variable) { switch (variable.getWrappedType().getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: return loadInt(variable.getSlot()); case Type.FLOAT: return loadFloat(variable.getSlot()); case Type.LONG: return loadLong(variable.getSlot()); case Type.DOUBLE: return loadDouble(variable.getSlot()); case Type.ARRAY: case Type.OBJECT: return loadObject(variable.getSlot()); default: throw new UncompilableNodeException("Attempted to load variable of type " + variable.getWrappedType()); } } public static RegisterNode storeVar(IRVariable variable) { switch (variable.getWrappedType().getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: return storeInt(variable.getSlot()); case Type.FLOAT: return storeFloat(variable.getSlot()); case Type.LONG: return storeLong(variable.getSlot()); case Type.DOUBLE: return storeDouble(variable.getSlot()); case Type.ARRAY: case Type.OBJECT: return storeObject(variable.getSlot()); default: throw new UncompilableNodeException("Attempted to store variable of type " + variable.getWrappedType()); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/SimpleNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; public enum SimpleNode implements CompilableNode { // Tux, will you nop sled with me? NOP(Opcodes.NOP), // Null push PUSH_NULL(Opcodes.ACONST_NULL), // Integer pushes PUSH_M1I(Opcodes.ICONST_M1), PUSH_0I(Opcodes.ICONST_0), PUSH_1I(Opcodes.ICONST_1), PUSH_2I(Opcodes.ICONST_2), PUSH_3I(Opcodes.ICONST_3), PUSH_4I(Opcodes.ICONST_4), PUSH_5I(Opcodes.ICONST_5), // Long pushes PUSH_0L(Opcodes.LCONST_0), PUSH_1L(Opcodes.LCONST_1), // Float pushes PUSH_0F(Opcodes.FCONST_0), PUSH_1F(Opcodes.FCONST_1), PUSH_2F(Opcodes.FCONST_2), // Double pushes PUSH_0D(Opcodes.DCONST_0), PUSH_1D(Opcodes.DCONST_1), // Array loads INT_ARRAY_LOAD(Opcodes.IALOAD), LONG_ARRAY_LOAD(Opcodes.LALOAD), FLOAT_ARRAY_LOAD(Opcodes.FALOAD), DOUBLE_ARRAY_LOAD(Opcodes.DALOAD), OBJECT_ARRAY_LOAD(Opcodes.AALOAD), BYTE_ARRAY_LOAD(Opcodes.BALOAD), CHAR_ARRAY_LOAD(Opcodes.CALOAD), SHORT_ARRAY_LOAD(Opcodes.SALOAD), // Array stores INT_ARRAY_STORE(Opcodes.IASTORE), LONG_ARRAY_STORE(Opcodes.LASTORE), FLOAT_ARRAY_STORE(Opcodes.FASTORE), DOUBLE_ARRAY_STORE(Opcodes.DASTORE), OBJECT_ARRAY_STORE(Opcodes.AASTORE), BYTE_ARRAY_STORE(Opcodes.BASTORE), CHAR_ARRAY_STORE(Opcodes.CASTORE), SHORT_ARRAY_STORE(Opcodes.SASTORE), // Stack stuff POP(Opcodes.POP), POP2(Opcodes.POP2), DUP(Opcodes.DUP), DUP_X1(Opcodes.DUP_X1), DUP_X2(Opcodes.DUP_X2), DUP2(Opcodes.DUP2), DUP2_X1(Opcodes.DUP2_X1), DUP2_X2(Opcodes.DUP2_X2), SWAP(Opcodes.SWAP), // Int math INT_ADD(Opcodes.IADD), INT_SUB(Opcodes.ISUB), INT_MUL(Opcodes.IMUL), INT_DIV(Opcodes.IDIV), INT_MOD(Opcodes.IREM), INT_NEG(Opcodes.INEG), INT_SHIFT_LEFT(Opcodes.ISHL), INT_SHIFT_RIGHT(Opcodes.ISHR), INT_UNSIGNED_SHIFT_RIGHT(Opcodes.IUSHR), INT_AND(Opcodes.IAND), INT_OR(Opcodes.IOR), INT_XOR(Opcodes.IXOR), // Long math LONG_ADD(Opcodes.LADD), LONG_SUB(Opcodes.LSUB), LONG_MUL(Opcodes.LMUL), LONG_DIV(Opcodes.LDIV), LONG_MOD(Opcodes.LREM), LONG_NEG(Opcodes.LNEG), LONG_SHIFT_LEFT(Opcodes.LSHL), LONG_SHIFT_RIGHT(Opcodes.LSHR), LONG_UNSIGNED_SHIFT_RIGHT(Opcodes.LUSHR), LONG_AND(Opcodes.LAND), LONG_OR(Opcodes.LOR), LONG_XOR(Opcodes.LXOR), // Float math FLOAT_ADD(Opcodes.FADD), FLOAT_SUB(Opcodes.FSUB), FLOAT_MUL(Opcodes.FMUL), FLOAT_DIV(Opcodes.FDIV), FLOAT_MOD(Opcodes.FREM), FLOAT_NEG(Opcodes.FNEG), // Double math DOUBLE_ADD(Opcodes.DADD), DOUBLE_SUB(Opcodes.DSUB), DOUBLE_MUL(Opcodes.DMUL), DOUBLE_DIV(Opcodes.DDIV), DOUBLE_MOD(Opcodes.DREM), DOUBLE_NEG(Opcodes.DNEG), // Int 2 XXX casts CAST_INT_TO_LONG(Opcodes.I2L), CAST_INT_TO_FLOAT(Opcodes.I2F), CAST_INT_TO_DOUBLE(Opcodes.I2D), CAST_INT_TO_BYTE(Opcodes.I2B), CAST_INT_TO_CHAR(Opcodes.I2C), CAST_INT_TO_SHORT(Opcodes.I2S), // Long 2 XXX casts CAST_LONG_TO_INT(Opcodes.L2I), CAST_LONG_TO_FLOAT(Opcodes.L2F), CAST_LONG_TO_DOUBLE(Opcodes.L2D), // Float 2 XXX casts CAST_FLOAT_TO_INT(Opcodes.F2I), CAST_FLOAT_TO_LONG(Opcodes.F2L), CAST_FLOAT_TO_DOUBLE(Opcodes.F2D), // Double 2 XXX casts CAST_DOUBLE_TO_INT(Opcodes.D2I), CAST_DOUBLE_TO_LONG(Opcodes.D2L), CAST_DOUBLE_TO_FLOAT(Opcodes.D2F), // Long.compare(first, second) COMPARE_LONGS(Opcodes.LCMP), // Float.compare(first, second) COMPARE_FLOAT_OR_M1I(Opcodes.FCMPL), // pushes -1 if 'first' or 'second' are NaN COMPARE_FLOAT_OR_1I(Opcodes.FCMPG), // pushes 1 if 'first' or 'second' are NaN // Double.compare(first, second) COMPARE_DOUBLE_OR_M1I(Opcodes.DCMPL), // pushes -1 if 'first' or 'second' are NaN COMPARE_DOUBLE_OR_1I(Opcodes.DCMPG), // pushes 1 if 'first' or 'second' are NaN // Returns RETURN_INT(Opcodes.IRETURN), RETURN_LONG(Opcodes.LRETURN), RETURN_FLOAT(Opcodes.FRETURN), RETURN_DOUBLE(Opcodes.DRETURN), RETURN_OBJECT(Opcodes.ARETURN), RETURN_VOID(Opcodes.RETURN), // array.length ARRAY_LENGTH(Opcodes.ARRAYLENGTH), // throw exceptionInstance THROW_EXCEPTION(Opcodes.ATHROW), // Monitor enter/exit ENTER_MONITOR(Opcodes.MONITORENTER), EXIT_MONITOR(Opcodes.MONITOREXIT); private int opcode; SimpleNode(int opcode) { this.opcode = opcode; } @Override public AbstractInsnNode getNode() { return new InsnNode(opcode); } public static SimpleNode getArrayStoreOp(WrappedType type) { // fixme maybe move to Utils? switch (type.getSort()) { case Type.BOOLEAN: case Type.INT: return INT_ARRAY_STORE; case Type.CHAR: return CHAR_ARRAY_STORE; case Type.BYTE: return BYTE_ARRAY_STORE; case Type.SHORT: return SHORT_ARRAY_STORE; case Type.FLOAT: return FLOAT_ARRAY_STORE; case Type.LONG: return LONG_ARRAY_STORE; case Type.DOUBLE: return DOUBLE_ARRAY_STORE; case Type.ARRAY: case Type.OBJECT: return OBJECT_ARRAY_STORE; default: throw new UncompilableNodeException("Attempted to get array store opcode for " + type); } } public static SimpleNode getArrayLoadOp(WrappedType type) { switch (type.getSort()) { case Type.BOOLEAN: case Type.INT: return INT_ARRAY_LOAD; case Type.CHAR: return CHAR_ARRAY_LOAD; case Type.BYTE: return BYTE_ARRAY_LOAD; case Type.SHORT: return SHORT_ARRAY_LOAD; case Type.FLOAT: return FLOAT_ARRAY_LOAD; case Type.LONG: return LONG_ARRAY_LOAD; case Type.DOUBLE: return DOUBLE_ARRAY_LOAD; case Type.ARRAY: case Type.OBJECT: return OBJECT_ARRAY_LOAD; default: throw new UncompilableNodeException("Attempted to get array load opcode for " + type); } } public static SimpleNode negateOpcodeFor(WrappedType type) { switch (type.getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: return INT_NEG; case Type.FLOAT: return FLOAT_NEG; case Type.LONG: return LONG_NEG; case Type.DOUBLE: return DOUBLE_NEG; default: throw new UncompilableNodeException("Attempted to get negate opcode for " + type); } } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/SwitchNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import xyz.itzsomebody.codegen.Utils; import java.util.List; public class SwitchNode implements CompilableNode { private final List keys; private final List labels; private final BytecodeLabel defaultLabel; public SwitchNode(List keys, List labels, BytecodeLabel defaultLabel) { this.keys = keys; this.labels = labels; this.defaultLabel = defaultLabel; } @Override public AbstractInsnNode getNode() { return new LookupSwitchInsnNode(defaultLabel.getLabel(), keys.stream().mapToInt(i -> i).toArray(), Utils.unwrapLabels(labels).toArray(new LabelNode[0])); } } ================================================ FILE: xyz.itzsomebody.codegen/src/main/java/xyz/itzsomebody/codegen/instructions/TypeNode.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; public class TypeNode implements CompilableNode { private final int opcode; private final WrappedType type; public TypeNode(int opcode, WrappedType type) { this.opcode = opcode; this.type = type; } @Override public AbstractInsnNode getNode() { return new TypeInsnNode(opcode, type.getInternalName()); } public static TypeNode newInstance(WrappedType type) { return new TypeNode(Opcodes.NEW, type); } public static TypeNode cast(WrappedType type) { return new TypeNode(Opcodes.CHECKCAST, type); } public static TypeNode instanceOf(WrappedType type) { return new TypeNode(Opcodes.INSTANCEOF, type); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/UtilsTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.codegen.instructions.ConstantNode; import java.util.List; public class UtilsTester { @Test public void testWrapMethodNodeParameters() { var dummyMethodNode = new MethodNode(); dummyMethodNode.desc = "(Ljava/lang/String;ZBCSIJFD)V"; List wrappedTypes = Utils.wrapMethodNodeParameters(dummyMethodNode); List expected = List.of( WrappedType.from(String.class), WrappedType.from(boolean.class), WrappedType.from(byte.class), WrappedType.from(char.class), WrappedType.from(short.class), WrappedType.from(int.class), WrappedType.from(long.class), WrappedType.from(float.class), WrappedType.from(double.class) ); Assert.assertEquals(expected, wrappedTypes); } @Test public void testWrapMethodParameters() throws Exception { var method = String.class.getMethod("getBytes", int.class, int.class, byte[].class, int.class); List wrappedTypes = Utils.wrapMethodParameters(method); List expected = List.of( WrappedType.from(int.class), WrappedType.from(int.class), WrappedType.from(byte[].class), WrappedType.from(int.class) ); Assert.assertEquals(expected, wrappedTypes); } @Test public void testWrapConstructorParameters() throws Exception { var constructor = String.class.getConstructor(byte[].class, String.class); List wrappedTypes = Utils.wrapConstructorParameters(constructor); List expected = List.of( WrappedType.from(byte[].class), WrappedType.from(String.class) ); Assert.assertEquals(expected, wrappedTypes); } @Test public void testUnwrapMethodDescriptor() { var expected = "(Ljava/lang/String;ZBCSIJFD)V"; var actual = Utils.unwrapMethodDescriptor(List.of( WrappedType.from(String.class), WrappedType.from(boolean.class), WrappedType.from(byte.class), WrappedType.from(char.class), WrappedType.from(short.class), WrappedType.from(int.class), WrappedType.from(long.class), WrappedType.from(float.class), WrappedType.from(double.class)), WrappedType.from(void.class) ); Assert.assertEquals(expected, actual); } @Test public void testUnpackConstants() { var expected = new Object[]{null, "test", false, 0, 0L, 0F, 0D, WrappedType.from(String.class)}; var actual = Utils.unpackConstants(List.of( ConstantNode.nullConst(), ConstantNode.stringConst("test"), ConstantNode.booleanConst(false), ConstantNode.intConst(0), ConstantNode.longConst(0L), ConstantNode.floatConst(0F), ConstantNode.doubleConst(0D), ConstantNode.classConst(WrappedType.from(String.class)) )); Assert.assertArrayEquals(expected, actual); } @Test public void testBoxForPrimitives() { // Test all primitive boxings Assert.assertEquals(WrappedType.from(Boolean.class), Utils.box(WrappedType.from(boolean.class))); Assert.assertEquals(WrappedType.from(Character.class), Utils.box(WrappedType.from(char.class))); Assert.assertEquals(WrappedType.from(Byte.class), Utils.box(WrappedType.from(byte.class))); Assert.assertEquals(WrappedType.from(Short.class), Utils.box(WrappedType.from(short.class))); Assert.assertEquals(WrappedType.from(Integer.class), Utils.box(WrappedType.from(int.class))); Assert.assertEquals(WrappedType.from(Long.class), Utils.box(WrappedType.from(long.class))); Assert.assertEquals(WrappedType.from(Float.class), Utils.box(WrappedType.from(float.class))); Assert.assertEquals(WrappedType.from(Double.class), Utils.box(WrappedType.from(double.class))); } @Test(expected = IllegalArgumentException.class) public void testBoxForNonPrimitive() { // Ensure exception is thrown when boxing non-primitive Utils.box(WrappedType.from(String.class)); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/WrappedTypeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; public class WrappedTypeTester { @Test public void testGetAbsent() { Assert.assertNotNull(WrappedType.getAbsent()); } @Test public void testIsInterface() { Assert.assertTrue(WrappedType.from(Dummy.class).isInterface()); Assert.assertFalse(WrappedType.from(int.class).isInterface()); Assert.assertFalse(WrappedType.from(String.class).isInterface()); } @Test public void testIsPrimitive() { Assert.assertTrue(WrappedType.from(boolean.class).isPrimitive()); Assert.assertTrue(WrappedType.from(char.class).isPrimitive()); Assert.assertTrue(WrappedType.from(byte.class).isPrimitive()); Assert.assertTrue(WrappedType.from(short.class).isPrimitive()); Assert.assertTrue(WrappedType.from(int.class).isPrimitive()); Assert.assertTrue(WrappedType.from(float.class).isPrimitive()); Assert.assertTrue(WrappedType.from(long.class).isPrimitive()); Assert.assertTrue(WrappedType.from(double.class).isPrimitive()); Assert.assertFalse(WrappedType.from(int[].class).isPrimitive()); Assert.assertFalse(WrappedType.from(String.class).isPrimitive()); Assert.assertFalse(WrappedType.from(Integer.class).isPrimitive()); } @Test public void testGetPrimitiveTypeForBoxedPrimitive() { Assert.assertEquals(WrappedType.from(boolean.class), WrappedType.from(Boolean.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(char.class), WrappedType.from(Character.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(byte.class), WrappedType.from(Byte.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(short.class), WrappedType.from(Short.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(int.class), WrappedType.from(Integer.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(float.class), WrappedType.from(Float.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(long.class), WrappedType.from(Long.class).getPrimitiveType()); Assert.assertEquals(WrappedType.from(double.class), WrappedType.from(Double.class).getPrimitiveType()); } @Test(expected = UncompilableNodeException.class) public void testGetPrimitiveTypeForNonBoxedPrimitive() { WrappedType.from(int.class).getPrimitiveType(); } @Test public void testIsBoxed() { Assert.assertTrue(WrappedType.from(Boolean.class).isBoxed()); Assert.assertTrue(WrappedType.from(Character.class).isBoxed()); Assert.assertTrue(WrappedType.from(Byte.class).isBoxed()); Assert.assertTrue(WrappedType.from(Short.class).isBoxed()); Assert.assertTrue(WrappedType.from(Integer.class).isBoxed()); Assert.assertTrue(WrappedType.from(Float.class).isBoxed()); Assert.assertTrue(WrappedType.from(Long.class).isBoxed()); Assert.assertTrue(WrappedType.from(Double.class).isBoxed()); Assert.assertFalse(WrappedType.from(Integer[].class).isBoxed()); Assert.assertFalse(WrappedType.from(int.class).isBoxed()); Assert.assertFalse(WrappedType.from(String.class).isBoxed()); } @Test public void testIsArray() { Assert.assertTrue(WrappedType.from(int[].class).isArray()); Assert.assertTrue(WrappedType.from(String[].class).isArray()); Assert.assertFalse(WrappedType.from(int.class).isArray()); Assert.assertFalse(WrappedType.from(String.class).isArray()); } @Test public void testIsIntType() { Assert.assertTrue(WrappedType.from(boolean.class).isIntType()); Assert.assertTrue(WrappedType.from(char.class).isIntType()); Assert.assertTrue(WrappedType.from(byte.class).isIntType()); Assert.assertTrue(WrappedType.from(short.class).isIntType()); Assert.assertTrue(WrappedType.from(int.class).isIntType()); Assert.assertFalse(WrappedType.from(float.class).isIntType()); Assert.assertFalse(WrappedType.from(long.class).isIntType()); Assert.assertFalse(WrappedType.from(double.class).isIntType()); Assert.assertFalse(WrappedType.from(int[].class).isPrimitive()); Assert.assertFalse(WrappedType.from(String.class).isPrimitive()); Assert.assertFalse(WrappedType.from(Integer.class).isPrimitive()); } @Test public void testUnwrap() { Assert.assertEquals("Z", WrappedType.from(boolean.class).unwrap()); Assert.assertEquals("C", WrappedType.from(char.class).unwrap()); Assert.assertEquals("S", WrappedType.from(short.class).unwrap()); Assert.assertEquals("B", WrappedType.from(byte.class).unwrap()); Assert.assertEquals("I", WrappedType.from(int.class).unwrap()); Assert.assertEquals("J", WrappedType.from(long.class).unwrap()); Assert.assertEquals("F", WrappedType.from(float.class).unwrap()); Assert.assertEquals("D", WrappedType.from(double.class).unwrap()); Assert.assertEquals("Ljava/lang/String;", WrappedType.from(String.class).unwrap()); Assert.assertEquals("[Ljava/lang/String;", WrappedType.from(String[].class).unwrap()); Assert.assertEquals("[I", WrappedType.from(int[].class).unwrap()); } @Test public void testFromClassName() { Assert.assertEquals(WrappedType.from(boolean.class), WrappedType.fromClassName("boolean", false)); Assert.assertEquals(WrappedType.from(char.class), WrappedType.fromClassName("char", false)); Assert.assertEquals(WrappedType.from(short.class), WrappedType.fromClassName("short", false)); Assert.assertEquals(WrappedType.from(byte.class), WrappedType.fromClassName("byte", false)); Assert.assertEquals(WrappedType.from(int.class), WrappedType.fromClassName("int", false)); Assert.assertEquals(WrappedType.from(long.class), WrappedType.fromClassName("long", false)); Assert.assertEquals(WrappedType.from(float.class), WrappedType.fromClassName("float", false)); Assert.assertEquals(WrappedType.from(double.class), WrappedType.fromClassName("double", false)); Assert.assertEquals(WrappedType.from(String.class), WrappedType.fromClassName("java.lang.String", false)); Assert.assertEquals(WrappedType.from(String[].class), WrappedType.fromClassName("java.lang.String[]", false)); } @Test public void testFromInternalName() { Assert.assertEquals(WrappedType.from(boolean.class), WrappedType.fromInternalName("Z", false)); Assert.assertEquals(WrappedType.from(char.class), WrappedType.fromInternalName("C", false)); Assert.assertEquals(WrappedType.from(short.class), WrappedType.fromInternalName("S", false)); Assert.assertEquals(WrappedType.from(byte.class), WrappedType.fromInternalName("B", false)); Assert.assertEquals(WrappedType.from(int.class), WrappedType.fromInternalName("I", false)); Assert.assertEquals(WrappedType.from(long.class), WrappedType.fromInternalName("J", false)); Assert.assertEquals(WrappedType.from(float.class), WrappedType.fromInternalName("F", false)); Assert.assertEquals(WrappedType.from(double.class), WrappedType.fromInternalName("D", false)); Assert.assertEquals(WrappedType.from(String.class), WrappedType.fromInternalName("java/lang/String", false)); Assert.assertEquals(WrappedType.from(String[].class), WrappedType.fromInternalName("[Ljava/lang/String;", false)); } @Test public void testFromClassNode() { var dummyClassNode = new ClassNode(); dummyClassNode.name = "xyz/itzsomebody/codegen/WrappedTypeTester$Dummy"; dummyClassNode.access = Opcodes.ACC_INTERFACE; Assert.assertEquals(WrappedType.from(Dummy.class), WrappedType.from(dummyClassNode)); } private interface Dummy { } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/IRVariableTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import xyz.itzsomebody.codegen.GenerationContext; public class IRVariableTester { @Test public void testGetIntTypeVariable() { var context = new GenerationContext(); var insns = context.newVariable(byte.class).getInstructions().compile(); Assert.assertEquals(Opcodes.ILOAD, insns.get(0).getOpcode()); } @Test public void testGetLongVariable() { var context = new GenerationContext(); var insns = context.newVariable(long.class).getInstructions().compile(); Assert.assertEquals(Opcodes.LLOAD, insns.get(0).getOpcode()); } @Test public void testGetFloatVariable() { var context = new GenerationContext(); var insns = context.newVariable(float.class).getInstructions().compile(); Assert.assertEquals(Opcodes.FLOAD, insns.get(0).getOpcode()); } @Test public void testGetDoubleVariable() { var context = new GenerationContext(); var insns = context.newVariable(double.class).getInstructions().compile(); Assert.assertEquals(Opcodes.DLOAD, insns.get(0).getOpcode()); } @Test public void testGetObjectVariable() { var context = new GenerationContext(); var insns = context.newVariable(String.class).getInstructions().compile(); Assert.assertEquals(Opcodes.ALOAD, insns.get(0).getOpcode()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRArithmeticExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRArithmeticExpressionTester { @Test public void testIntMathGeneration() { var block = intAdd(intConst(5), intConst(-3)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ICONST_5, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.BIPUSH, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.IADD, insns.get(2).getOpcode()); } @Test public void testLongMathGeneration() { var block = longMod(longConst(11), longConst(1)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.LDC, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.LCONST_1, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.LREM, insns.get(2).getOpcode()); } @Test public void testFloatMathGeneration() { var block = floatMul(floatConst(0F), floatConst(2.1f)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.FCONST_0, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.LDC, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.FMUL, insns.get(2).getOpcode()); } @Test public void testDoubleMathGeneration() { var block = doubleSub(doubleConst(1D), doubleConst(8.9999D)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.DCONST_1, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.LDC, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.DSUB, insns.get(2).getOpcode()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRArrayLengthTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import java.util.stream.IntStream; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRArrayLengthTester { @Test public void testForPrimitiveArray() { var block = arrayLength(newArray(int.class, intConst(0), intConst(1))).getInstructions(); var insns = block.compile(); var expectedOpcodes = new int[]{ Opcodes.ICONST_2, Opcodes.NEWARRAY, Opcodes.DUP, Opcodes.ICONST_0, Opcodes.ICONST_0, Opcodes.IASTORE, Opcodes.DUP, Opcodes.ICONST_1, Opcodes.ICONST_1, Opcodes.IASTORE, Opcodes.ARRAYLENGTH }; IntStream.range(0, insns.size()).forEach(i -> Assert.assertEquals(expectedOpcodes[i], insns.get(i).getOpcode())); } @Test public void testForStringArray() { var block = arrayLength(newArray(String.class, stringConst("tux"), stringConst("tucks"))).getInstructions(); var insns = block.compile(); var expectedOpcodes = new int[]{ Opcodes.ICONST_2, Opcodes.ANEWARRAY, Opcodes.DUP, Opcodes.ICONST_0, Opcodes.LDC, Opcodes.AASTORE, Opcodes.DUP, Opcodes.ICONST_1, Opcodes.LDC, Opcodes.AASTORE, Opcodes.ARRAYLENGTH }; IntStream.range(0, insns.size()).forEach(i -> Assert.assertEquals(expectedOpcodes[i], insns.get(i).getOpcode())); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRCastExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRCastExpressionTester { @Test public void testCastBooleanToShort() { var block = cast(booleanConst(false), WrappedType.from(short.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ICONST_0, insns.get(0).getOpcode()); } @Test public void testCastDoubleToShort() { var block = cast(doubleConst(99.9999D), WrappedType.from(short.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.LDC, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.D2I, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.I2S, insns.get(2).getOpcode()); var ldc = (LdcInsnNode) insns.get(0); Assert.assertEquals(99.9999D, ldc.cst); } @Test public void testCastPrimitiveToEquivalentBoxedPrimitive() { var block = cast(booleanConst(false), WrappedType.from(Boolean.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ICONST_0, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.INVOKESTATIC, insns.get(1).getOpcode()); var invoke = (MethodInsnNode) insns.get(1); Assert.assertEquals("java/lang/Boolean", invoke.owner); Assert.assertEquals("valueOf", invoke.name); Assert.assertEquals("(Z)Ljava/lang/Boolean;", invoke.desc); } @Test public void testCastPrimitiveToNonPrimitive() { var block = cast(intConst(5), WrappedType.from(Number.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ICONST_5, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.INVOKESTATIC, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.CHECKCAST, insns.get(2).getOpcode()); var invoke = (MethodInsnNode) insns.get(1); Assert.assertEquals("java/lang/Integer", invoke.owner); Assert.assertEquals("valueOf", invoke.name); Assert.assertEquals("(I)Ljava/lang/Integer;", invoke.desc); var cast = (TypeInsnNode) insns.get(2); Assert.assertEquals("java/lang/Number", cast.desc); } @Test public void testCastBoxedPrimitiveToPrimitive() { var block = cast(cast(intConst(5), WrappedType.from(Integer.class)), WrappedType.from(long.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ICONST_5, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.INVOKESTATIC, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.INVOKEVIRTUAL, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.I2L, insns.get(3).getOpcode()); var invoke1 = (MethodInsnNode) insns.get(1); Assert.assertEquals("java/lang/Integer", invoke1.owner); Assert.assertEquals("valueOf", invoke1.name); Assert.assertEquals("(I)Ljava/lang/Integer;", invoke1.desc); var invoke2 = (MethodInsnNode) insns.get(2); Assert.assertEquals("java/lang/Integer", invoke2.owner); Assert.assertEquals("intValue", invoke2.name); Assert.assertEquals("()I", invoke2.desc); } @Test public void testCastBoxedPrimitiveToNonPrimitive() { var block = cast(cast(intConst(5), WrappedType.from(Integer.class)), WrappedType.from(Number.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ICONST_5, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.INVOKESTATIC, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.CHECKCAST, insns.get(2).getOpcode()); var invoke = (MethodInsnNode) insns.get(1); Assert.assertEquals("java/lang/Integer", invoke.owner); Assert.assertEquals("valueOf", invoke.name); Assert.assertEquals("(I)Ljava/lang/Integer;", invoke.desc); var cast = (TypeInsnNode) insns.get(2); Assert.assertEquals("java/lang/Number", cast.desc); } @Test public void testCastNonPrimitiveToPrimitive() { // Don't try this at home lol var block = cast(cast(nullConst(Number.class), WrappedType.from(Integer.class)), WrappedType.from(long.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.CHECKCAST, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.INVOKEVIRTUAL, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.I2L, insns.get(3).getOpcode()); var cast = (TypeInsnNode) insns.get(1); Assert.assertEquals("java/lang/Integer", cast.desc); var invoke = (MethodInsnNode) insns.get(2); Assert.assertEquals("java/lang/Integer", invoke.owner); Assert.assertEquals("intValue", invoke.name); Assert.assertEquals("()I", invoke.desc); } @Test public void testCastNonPrimitiveToNonPrimitive() { var block = cast(nullConst(String.class), WrappedType.from(CharSequence.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.CHECKCAST, insns.get(1).getOpcode()); var cast = (TypeInsnNode) insns.get(1); Assert.assertEquals("java/lang/CharSequence", cast.desc); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRConstantTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.ConstantDynamic; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import java.lang.invoke.MethodHandles; import java.util.Collections; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRConstantTester { @Test public void testDynamicConst() throws Exception { var block = dynamicConst("tux", WrappedType.from(String.class), WrappedHandle.getInvokeStaticHandle(IRConstantTester.class.getMethod("dynamicTester", MethodHandles.Lookup.class, String.class, Class.class)), Collections.emptyList()).getInstructions(); var insn = block.compile().getFirst(); Assert.assertTrue(insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof ConstantDynamic); var dynamic = (ConstantDynamic) ((LdcInsnNode) insn).cst; var handle = dynamic.getBootstrapMethod(); Assert.assertEquals(Type.getInternalName(IRConstantTester.class), handle.getOwner()); Assert.assertEquals("dynamicTester", handle.getName()); Assert.assertEquals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/String;", handle.getDesc()); Assert.assertEquals("tux", dynamic.getName()); Assert.assertEquals("Ljava/lang/String;", dynamic.getDescriptor()); } @Test public void testNullConst() { var block = nullConst(String.class).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); } @Test public void testIntConst() { Assert.assertEquals(Opcodes.ICONST_0, intConst(0).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Opcodes.BIPUSH, intConst(Byte.MAX_VALUE).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Byte.MAX_VALUE, ((IntInsnNode) intConst(Byte.MAX_VALUE).getInstructions().compile().get(0)).operand); Assert.assertEquals(Opcodes.SIPUSH, intConst(Short.MAX_VALUE).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Short.MAX_VALUE, ((IntInsnNode) intConst(Short.MAX_VALUE).getInstructions().compile().get(0)).operand); Assert.assertEquals(Opcodes.LDC, intConst(Integer.MAX_VALUE).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Integer.MAX_VALUE, ((LdcInsnNode) intConst(Integer.MAX_VALUE).getInstructions().compile().get(0)).cst); } @Test public void testLongConst() { Assert.assertEquals(Opcodes.LCONST_0, longConst(0L).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Opcodes.LDC, longConst(Long.MAX_VALUE).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Long.MAX_VALUE, ((LdcInsnNode) longConst(Long.MAX_VALUE).getInstructions().compile().get(0)).cst); } @Test public void testFloatConst() { Assert.assertEquals(Opcodes.FCONST_0, floatConst(0F).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Opcodes.LDC, floatConst(Float.MAX_VALUE).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Float.MAX_VALUE, ((LdcInsnNode) floatConst(Float.MAX_VALUE).getInstructions().compile().get(0)).cst); } @Test public void testDoubleConst() { Assert.assertEquals(Opcodes.DCONST_0, doubleConst(0D).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Opcodes.LDC, doubleConst(Double.MAX_VALUE).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Double.MAX_VALUE, ((LdcInsnNode) doubleConst(Double.MAX_VALUE).getInstructions().compile().get(0)).cst); } @Test public void testStringConst() { Assert.assertEquals(Opcodes.LDC, stringConst("tux").getInstructions().compile().get(0).getOpcode()); Assert.assertEquals("tux", ((LdcInsnNode) stringConst("tux").getInstructions().compile().get(0)).cst); } @Test public void testClassConst() { Assert.assertEquals(Opcodes.LDC, classConst(String.class).getInstructions().compile().get(0).getOpcode()); Assert.assertEquals(Type.getType(String.class), ((LdcInsnNode) classConst(String.class).getInstructions().compile().get(0)).cst); } public static String dynamicTester(MethodHandles.Lookup lookup, String name, Class type) { return "test"; } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRGetArrayElementExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRGetArrayElementExpressionTester { @Test public void testLoadBooleanElement() { var block = getArrayElement(nullConst(boolean.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.IALOAD, insns.get(2).getOpcode()); } @Test public void testLoadByteElement() { var block = getArrayElement(nullConst(byte.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.BALOAD, insns.get(2).getOpcode()); } @Test public void testLoadShortElement() { var block = getArrayElement(nullConst(short.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.SALOAD, insns.get(2).getOpcode()); } @Test public void testLoadCharElement() { var block = getArrayElement(nullConst(char.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.CALOAD, insns.get(2).getOpcode()); } @Test public void testLoadIntElement() { var block = getArrayElement(nullConst(int.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.IALOAD, insns.get(2).getOpcode()); } @Test public void testLoadLongElement() { var block = getArrayElement(nullConst(long.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.LALOAD, insns.get(2).getOpcode()); } @Test public void testLoadFloatElement() { var block = getArrayElement(nullConst(float.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.FALOAD, insns.get(2).getOpcode()); } @Test public void testLoadDoubleElement() { var block = getArrayElement(nullConst(double.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.DALOAD, insns.get(2).getOpcode()); } @Test public void testLoadObjectElement() { var block = getArrayElement(nullConst(String.class), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.AALOAD, insns.get(2).getOpcode()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRGetFieldExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.FieldInsnNode; import xyz.itzsomebody.codegen.WrappedType; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRGetFieldExpressionTester { @Test public void testGetObjectField() throws Exception { var fin = (FieldInsnNode) getField(nullConst(WrappedType.from(TestClass.class)), TestClass.class.getField("exampleField")).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.GETFIELD, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(TestClass.class), fin.owner); Assert.assertEquals("exampleField", fin.name); Assert.assertEquals("Ljava/lang/String;", fin.desc); } @Test public void testGetPrimitiveField() throws Exception { var fin = (FieldInsnNode) getField(nullConst(WrappedType.from(TestClass.class)), TestClass.class.getField("examplePrimitiveField")).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.GETFIELD, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(TestClass.class), fin.owner); Assert.assertEquals("examplePrimitiveField", fin.name); Assert.assertEquals("B", fin.desc); } @Test public void testGetObjectStatic() throws Exception { var fin = (FieldInsnNode) getStatic(TestClass.class.getField("exampleStaticField")).getInstructions().compile().get(0); Assert.assertEquals(Opcodes.GETSTATIC, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(TestClass.class), fin.owner); Assert.assertEquals("exampleStaticField", fin.name); Assert.assertEquals("Ljava/lang/String;", fin.desc); } @Test public void testGetPrimitiveStatic() throws Exception { var fin = (FieldInsnNode) getStatic(TestClass.class.getField("exampleStaticPrimitiveField")).getInstructions().compile().get(0); Assert.assertEquals(Opcodes.GETSTATIC, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(TestClass.class), fin.owner); Assert.assertEquals("exampleStaticPrimitiveField", fin.name); Assert.assertEquals("B", fin.desc); } public static class TestClass { public String exampleField; public byte examplePrimitiveField; public static String exampleStaticField; public static byte exampleStaticPrimitiveField; } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRInstanceOfExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; import static xyz.itzsomebody.codegen.expressions.IRExpressions.instanceOf; import static xyz.itzsomebody.codegen.expressions.IRExpressions.nullConst; public class IRInstanceOfExpressionTester { @Test public void testInstanceOfClass() { var tin = (TypeInsnNode) instanceOf(nullConst(Integer.class), Number.class).getInstructions().compile().get(1); Assert.assertEquals("java/lang/Number", tin.desc); } @Test public void testInstanceOfWrappedType() { var tin = (TypeInsnNode) instanceOf(nullConst(Integer.class), WrappedType.from(Number.class)).getInstructions().compile().get(1); Assert.assertEquals("java/lang/Number", tin.desc); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRInvocationExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodInsnNode; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRInvocationExpressionTester { @Test public void testInvokeStatic() throws Exception { var min = (MethodInsnNode) invokeStatic(DummyClass.class.getMethod("dummyStatic", String.class, int[].class)).getInstructions().compile().get(0); Assert.assertEquals(Opcodes.INVOKESTATIC, min.getOpcode()); Assert.assertEquals(Type.getInternalName(DummyClass.class), min.owner); Assert.assertEquals("dummyStatic", min.name); Assert.assertEquals("(Ljava/lang/String;[I)V", min.desc); } @Test public void testInvokeVirtual() throws Exception { var min = (MethodInsnNode) invokeVirtual(nullConst(DummyClass.class), DummyClass.class.getMethod("dummyMethod", String.class, byte.class)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.INVOKEVIRTUAL, min.getOpcode()); Assert.assertEquals(Type.getInternalName(DummyClass.class), min.owner); Assert.assertEquals("dummyMethod", min.name); Assert.assertEquals("(Ljava/lang/String;B)V", min.desc); } @Test public void testInvokeInterface() throws Exception { var min = (MethodInsnNode) invokeVirtual(nullConst(DummyInterface.class), DummyInterface.class.getMethod("dummyInterfaceMethod", String.class, boolean.class)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.INVOKEINTERFACE, min.getOpcode()); Assert.assertEquals(Type.getInternalName(DummyInterface.class), min.owner); Assert.assertEquals("dummyInterfaceMethod", min.name); Assert.assertEquals("(Ljava/lang/String;Z)V", min.desc); } public interface DummyInterface { void dummyInterfaceMethod(String tux, boolean tucks); } public static class DummyClass implements DummyInterface { public void dummyMethod(String tux, byte tucks) { } public static void dummyStatic(String tux, int[] tucks) { } @Override public void dummyInterfaceMethod(String tux, boolean tucks) { } } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRInvokeDynamicExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.Collections; import java.util.List; import static xyz.itzsomebody.codegen.expressions.IRExpressions.invokeDynamic; import static xyz.itzsomebody.codegen.expressions.IRExpressions.stringConst; public class IRInvokeDynamicExpressionTester { @Test public void testInvokeDynamicWithMethodBootstrap() throws Exception { var method = IRInvokeDynamicExpressionTester.class.getMethod("dummyBootstrap", MethodHandles.Lookup.class, String.class, MethodType.class); var block = invokeDynamic( "tucks", List.of(stringConst("tux"), stringConst("tuks")), List.of(WrappedType.from(String.class), WrappedType.from(String.class)), WrappedType.from(String.class), method, Collections.emptyList() ).getInstructions(); var insns = block.compile(); Assert.assertEquals("tux", ((LdcInsnNode) insns.get(0)).cst); Assert.assertEquals("tuks", ((LdcInsnNode) insns.get(1)).cst); Assert.assertEquals(Opcodes.INVOKEDYNAMIC, insns.get(2).getOpcode()); var indy = (InvokeDynamicInsnNode) insns.get(2); var handle = indy.bsm; Assert.assertEquals("tucks", indy.name); Assert.assertEquals("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", indy.desc); Assert.assertEquals(Type.getInternalName(IRInvokeDynamicExpressionTester.class), handle.getOwner()); Assert.assertEquals("dummyBootstrap", handle.getName()); Assert.assertEquals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", handle.getDesc()); } @Test public void testInvokeDynamicWithWrappedHandleBootstrap() throws Exception { var method = IRInvokeDynamicExpressionTester.class.getMethod("dummyBootstrap", MethodHandles.Lookup.class, String.class, MethodType.class); var block = invokeDynamic( "tucks", List.of(stringConst("tux"), stringConst("tuks")), List.of(WrappedType.from(String.class), WrappedType.from(String.class)), WrappedType.from(String.class), WrappedHandle.getInvokeStaticHandle(method), Collections.emptyList() ).getInstructions(); var insns = block.compile(); Assert.assertEquals("tux", ((LdcInsnNode) insns.get(0)).cst); Assert.assertEquals("tuks", ((LdcInsnNode) insns.get(1)).cst); Assert.assertEquals(Opcodes.INVOKEDYNAMIC, insns.get(2).getOpcode()); var indy = (InvokeDynamicInsnNode) insns.get(2); var handle = indy.bsm; Assert.assertEquals("tucks", indy.name); Assert.assertEquals("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", indy.desc); Assert.assertEquals(Type.getInternalName(IRInvokeDynamicExpressionTester.class), handle.getOwner()); Assert.assertEquals("dummyBootstrap", handle.getName()); Assert.assertEquals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", handle.getDesc()); } public static CallSite dummyBootstrap(MethodHandles.Lookup lookup, String name, MethodType type) { return null; } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRNegateExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.InsnNode; import xyz.itzsomebody.codegen.exceptions.UncompilableNodeException; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRNegateExpressionTester { @Test public void testNegateBoolean() { var insn = (InsnNode) negate(booleanConst(false)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.INEG, insn.getOpcode()); } @Test public void testNegateInt() { var insn = (InsnNode) negate(intConst(0)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.INEG, insn.getOpcode()); } @Test public void testNegateLong() { var insn = (InsnNode) negate(longConst(0L)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.LNEG, insn.getOpcode()); } @Test public void testNegateFloat() { var insn = (InsnNode) negate(floatConst(0F)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.FNEG, insn.getOpcode()); } @Test public void testNegateDouble() { var insn = (InsnNode) negate(doubleConst(0D)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.DNEG, insn.getOpcode()); } @Test(expected = UncompilableNodeException.class) public void ensureExceptionThrownOnNonNegatableOperand() { negate(nullConst(String.class)).getInstructions(); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRNewArrayExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.IntInsnNode; import java.util.stream.IntStream; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRNewArrayExpressionTester { @Test public void testForPrimitiveArray() { var block = newArray(int.class, intConst(0), intConst(1)).getInstructions(); var insns = block.compile(); var expectedOpcodes = new int[]{ Opcodes.ICONST_2, Opcodes.NEWARRAY, Opcodes.DUP, Opcodes.ICONST_0, Opcodes.ICONST_0, Opcodes.IASTORE, Opcodes.DUP, Opcodes.ICONST_1, Opcodes.ICONST_1, Opcodes.IASTORE, }; IntStream.range(0, insns.size()).forEach(i -> Assert.assertEquals(expectedOpcodes[i], insns.get(i).getOpcode())); Assert.assertEquals(Opcodes.T_INT, ((IntInsnNode) insns.get(1)).operand); } @Test public void testForStringArray() { var block = newArray(String.class, stringConst("tux"), stringConst("tucks")).getInstructions(); var insns = block.compile(); var expectedOpcodes = new int[]{ Opcodes.ICONST_2, Opcodes.ANEWARRAY, Opcodes.DUP, Opcodes.ICONST_0, Opcodes.LDC, Opcodes.AASTORE, Opcodes.DUP, Opcodes.ICONST_1, Opcodes.LDC, Opcodes.AASTORE, }; IntStream.range(0, insns.size()).forEach(i -> Assert.assertEquals(expectedOpcodes[i], insns.get(i).getOpcode())); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRNewInstanceExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; import java.util.Collections; import static xyz.itzsomebody.codegen.expressions.IRExpressions.newInstance; public class IRNewInstanceExpressionTester { @Test public void testNewInstanceViaConstructor() throws Exception { var insns = newInstance(String.class.getConstructor()).getInstructions().compile(); var newOp = (TypeInsnNode) insns.get(0); Assert.assertEquals("java/lang/String", newOp.desc); Assert.assertEquals(Opcodes.DUP, insns.get(1).getOpcode()); var invoke = (MethodInsnNode) insns.get(2); Assert.assertEquals("java/lang/String", invoke.owner); Assert.assertEquals("", invoke.name); Assert.assertEquals("()V", invoke.desc); } @Test public void testNewInstanceViaWrappedType() throws Exception { var insns = newInstance(WrappedType.from(String.class), Collections.emptyList(), Collections.emptyList()).getInstructions().compile(); var newOp = (TypeInsnNode) insns.get(0); Assert.assertEquals("java/lang/String", newOp.desc); Assert.assertEquals(Opcodes.DUP, insns.get(1).getOpcode()); var invoke = (MethodInsnNode) insns.get(2); Assert.assertEquals("java/lang/String", invoke.owner); Assert.assertEquals("", invoke.name); Assert.assertEquals("()V", invoke.desc); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRReturnExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRReturnExpressionTester { @Test public void testReturnBoolean() { Assert.assertEquals(Opcodes.IRETURN, returnMe(booleanConst(false)).getInstructions().compile().get(1).getOpcode()); } @Test public void testReturnInt() { Assert.assertEquals(Opcodes.IRETURN, returnMe(intConst(0)).getInstructions().compile().get(1).getOpcode()); } @Test public void testReturnLong() { Assert.assertEquals(Opcodes.LRETURN, returnMe(longConst(0L)).getInstructions().compile().get(1).getOpcode()); } @Test public void testReturnFloat() { Assert.assertEquals(Opcodes.FRETURN, returnMe(floatConst(0F)).getInstructions().compile().get(1).getOpcode()); } @Test public void testReturnDouble() { Assert.assertEquals(Opcodes.DRETURN, returnMe(doubleConst(0D)).getInstructions().compile().get(1).getOpcode()); } @Test public void testReturnObject() { Assert.assertEquals(Opcodes.ARETURN, returnMe(nullConst(String.class)).getInstructions().compile().get(1).getOpcode()); } @Test public void testReturnNothing() { Assert.assertEquals(Opcodes.RETURN, returnMe(null).getInstructions().compile().get(0).getOpcode()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRSetArrayElementExpressionTester.java ================================================ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRSetArrayElementExpressionTester { @Test public void testStoreBooleanElement() { var block = setArrayElement(nullConst(boolean.class), intConst(0), booleanConst(false)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.IASTORE, insns.get(3).getOpcode()); } @Test public void testStoreByteElement() { var block = setArrayElement(nullConst(byte.class), intConst(0), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.BASTORE, insns.get(3).getOpcode()); } @Test public void testStoreShortElement() { var block = setArrayElement(nullConst(short.class), intConst(0), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.SASTORE, insns.get(3).getOpcode()); } @Test public void testStoreCharElement() { var block = setArrayElement(nullConst(char.class), intConst(0), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.CASTORE, insns.get(3).getOpcode()); } @Test public void testStoreIntElement() { var block = setArrayElement(nullConst(int.class), intConst(0), intConst(0)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.IASTORE, insns.get(3).getOpcode()); } @Test public void testStoreLongElement() { var block = setArrayElement(nullConst(long.class), intConst(0), longConst(0L)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.LCONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.LASTORE, insns.get(3).getOpcode()); } @Test public void testStoreFloatElement() { var block = setArrayElement(nullConst(float.class), intConst(0), floatConst(0F)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.FCONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.FASTORE, insns.get(3).getOpcode()); } @Test public void testStoreDoubleElement() { var block = setArrayElement(nullConst(double.class), intConst(0), doubleConst(0D)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.DCONST_0, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.DASTORE, insns.get(3).getOpcode()); } @Test public void testStoreObjectElement() { var block = setArrayElement(nullConst(String.class), intConst(0), nullConst(String.class)).getInstructions(); var insns = block.compile(); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ICONST_0, insns.get(1).getOpcode()); Assert.assertEquals(Opcodes.ACONST_NULL, insns.get(2).getOpcode()); Assert.assertEquals(Opcodes.AASTORE, insns.get(3).getOpcode()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRSetFieldExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.FieldInsnNode; import xyz.itzsomebody.codegen.WrappedType; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRSetFieldExpressionTester { @Test public void testSetObjectField() throws Exception { var fin = (FieldInsnNode) setField(nullConst(WrappedType.from(IRSetFieldExpressionTester.TestClass.class)), IRSetFieldExpressionTester.TestClass.class.getField("exampleField"), nullConst(String.class)).getInstructions().compile().get(2); Assert.assertEquals(Opcodes.PUTFIELD, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(IRSetFieldExpressionTester.TestClass.class), fin.owner); Assert.assertEquals("exampleField", fin.name); Assert.assertEquals("Ljava/lang/String;", fin.desc); } @Test public void testSetPrimitiveField() throws Exception { var fin = (FieldInsnNode) setField(nullConst(WrappedType.from(IRSetFieldExpressionTester.TestClass.class)), IRSetFieldExpressionTester.TestClass.class.getField("examplePrimitiveField"), intConst(0)).getInstructions().compile().get(2); Assert.assertEquals(Opcodes.PUTFIELD, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(IRSetFieldExpressionTester.TestClass.class), fin.owner); Assert.assertEquals("examplePrimitiveField", fin.name); Assert.assertEquals("B", fin.desc); } @Test public void testSetObjectStatic() throws Exception { var fin = (FieldInsnNode) setStatic(IRSetFieldExpressionTester.TestClass.class.getField("exampleStaticField"), nullConst(String.class)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.PUTSTATIC, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(IRSetFieldExpressionTester.TestClass.class), fin.owner); Assert.assertEquals("exampleStaticField", fin.name); Assert.assertEquals("Ljava/lang/String;", fin.desc); } @Test public void testSetPrimitiveStatic() throws Exception { var fin = (FieldInsnNode) setStatic(IRSetFieldExpressionTester.TestClass.class.getField("exampleStaticPrimitiveField"), intConst(0)).getInstructions().compile().get(1); Assert.assertEquals(Opcodes.PUTSTATIC, fin.getOpcode()); Assert.assertEquals(Type.getInternalName(IRSetFieldExpressionTester.TestClass.class), fin.owner); Assert.assertEquals("exampleStaticPrimitiveField", fin.name); Assert.assertEquals("B", fin.desc); } public static class TestClass { public String exampleField; public byte examplePrimitiveField; public static String exampleStaticField; public static byte exampleStaticPrimitiveField; } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/expressions/predefined/IRSetVariableExpressionTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.expressions.predefined; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import xyz.itzsomebody.codegen.GenerationContext; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; public class IRSetVariableExpressionTester { @Test public void testSetIntTypeVariable() { var context = new GenerationContext(); var insns = context.newVariable(byte.class).set(intConst(0)).getInstructions().compile(); Assert.assertEquals(Opcodes.ICONST_0, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ISTORE, insns.get(1).getOpcode()); } @Test public void testSetLongVariable() { var context = new GenerationContext(); var insns = context.newVariable(long.class).set(longConst(0L)).getInstructions().compile(); Assert.assertEquals(Opcodes.LCONST_0, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.LSTORE, insns.get(1).getOpcode()); } @Test public void testSetFloatVariable() { var context = new GenerationContext(); var insns = context.newVariable(float.class).set(floatConst(0F)).getInstructions().compile(); Assert.assertEquals(Opcodes.FCONST_0, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.FSTORE, insns.get(1).getOpcode()); } @Test public void testSetDoubleVariable() { var context = new GenerationContext(); var insns = context.newVariable(double.class).set(doubleConst(0)).getInstructions().compile(); Assert.assertEquals(Opcodes.DCONST_0, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.DSTORE, insns.get(1).getOpcode()); } @Test public void testSetObjectVariable() { var context = new GenerationContext(); var insns = context.newVariable(String.class).set(stringConst("tucks")).getInstructions().compile(); Assert.assertEquals(Opcodes.LDC, insns.get(0).getOpcode()); Assert.assertEquals(Opcodes.ASTORE, insns.get(1).getOpcode()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/BytecodeLabelTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; public class BytecodeLabelTester { @Test public void ensureCreatedLabelsAreUnique() { Assert.assertNotEquals(new BytecodeLabel().getLabel(), new BytecodeLabel().getLabel()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/ConstantNodeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import xyz.itzsomebody.codegen.WrappedType; public class ConstantNodeTester { @Test public void testNullConst() { Assert.assertNull(ConstantNode.nullConst().getValue()); Assert.assertEquals(Opcodes.ACONST_NULL, ConstantNode.nullConst().getNode().getOpcode()); } @Test public void testBooleanConst() { Assert.assertTrue((Boolean) ConstantNode.booleanConst(true).getValue()); Assert.assertNotEquals(Opcodes.ICONST_0, ConstantNode.booleanConst(true).getNode().getOpcode()); Assert.assertFalse((Boolean) ConstantNode.booleanConst(false).getValue()); Assert.assertEquals(Opcodes.ICONST_0, ConstantNode.booleanConst(false).getNode().getOpcode()); } @Test public void testIntConst() { Assert.assertEquals(Integer.MIN_VALUE, ConstantNode.intConst(Integer.MIN_VALUE).getValue()); Assert.assertEquals(Opcodes.LDC, ConstantNode.intConst(Integer.MIN_VALUE).getNode().getOpcode()); Assert.assertEquals(Opcodes.SIPUSH, ConstantNode.intConst(Short.MIN_VALUE).getNode().getOpcode()); Assert.assertEquals(Opcodes.BIPUSH, ConstantNode.intConst(Byte.MIN_VALUE).getNode().getOpcode()); Assert.assertEquals(Opcodes.ICONST_M1, ConstantNode.intConst(-1).getNode().getOpcode()); } @Test public void testFloatConst() { Assert.assertEquals(Float.MIN_VALUE, ConstantNode.floatConst(Float.MIN_VALUE).getValue()); Assert.assertEquals(Opcodes.LDC, ConstantNode.floatConst(Float.MIN_VALUE).getNode().getOpcode()); Assert.assertEquals(Opcodes.FCONST_0, ConstantNode.floatConst(0F).getNode().getOpcode()); } @Test public void testDoubleConst() { Assert.assertEquals(Double.MIN_VALUE, ConstantNode.doubleConst(Double.MIN_VALUE).getValue()); Assert.assertEquals(Opcodes.LDC, ConstantNode.doubleConst(Double.MIN_VALUE).getNode().getOpcode()); Assert.assertEquals(Opcodes.DCONST_0, ConstantNode.doubleConst(0D).getNode().getOpcode()); } @Test public void testStringConst() { Assert.assertEquals("tucks", ConstantNode.stringConst("tucks").getValue()); Assert.assertEquals(Opcodes.LDC, ConstantNode.stringConst("tux").getNode().getOpcode()); } @Test public void testClassConst() { Assert.assertEquals(WrappedType.from(String.class), ConstantNode.classConst(WrappedType.from(String.class)).getValue()); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/FieldAccessNodeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.FieldInsnNode; import xyz.itzsomebody.codegen.WrappedType; public class FieldAccessNodeTester { @Test public void testGetStatic() { var getStatic = (FieldInsnNode) FieldAccessNode.getStatic(WrappedType.from(Integer.class), "TYPE", WrappedType.from(Class.class)).getNode(); Assert.assertEquals(Opcodes.GETSTATIC, getStatic.getOpcode()); Assert.assertEquals("java/lang/Integer", getStatic.owner); Assert.assertEquals("TYPE", getStatic.name); Assert.assertEquals("Ljava/lang/Class;", getStatic.desc); } @Test public void testPutStatic() { var putStatic = (FieldInsnNode) FieldAccessNode.putStatic(WrappedType.from(String.class), "hash", WrappedType.from(int.class)).getNode(); Assert.assertEquals(Opcodes.PUTSTATIC, putStatic.getOpcode()); Assert.assertEquals("java/lang/String", putStatic.owner); Assert.assertEquals("hash", putStatic.name); Assert.assertEquals("I", putStatic.desc); } @Test public void testGetField() { var getField = (FieldInsnNode) FieldAccessNode.getField(WrappedType.from(Integer.class), "value", WrappedType.from(int.class)).getNode(); Assert.assertEquals(Opcodes.GETFIELD, getField.getOpcode()); Assert.assertEquals("java/lang/Integer", getField.owner); Assert.assertEquals("value", getField.name); Assert.assertEquals("I", getField.desc); } @Test public void testPutField() { var putField = (FieldInsnNode) FieldAccessNode.putField(WrappedType.from(String.class), "value", WrappedType.from(byte[].class)).getNode(); Assert.assertEquals(Opcodes.PUTFIELD, putField.getOpcode()); Assert.assertEquals("java/lang/String", putField.owner); Assert.assertEquals("value", putField.name); Assert.assertEquals("[B", putField.desc); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/InvokeDynamicNodeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import xyz.itzsomebody.codegen.WrappedHandle; import xyz.itzsomebody.codegen.WrappedType; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.Collections; import java.util.List; public class InvokeDynamicNodeTester { @Test public void testInvokeDynamicWithMethod() throws Exception { var method = InvokeDynamicNodeTester.class.getMethod("testBootstrap", MethodHandles.Lookup.class, String.class, MethodType.class); var invoke = (InvokeDynamicInsnNode) InvokeDynamicNode.invokeDynamic("tux", List.of(WrappedType.from(String.class)), WrappedType.from(void.class), method, Collections.emptyList()).getNode(); Assert.assertEquals("tux", invoke.name); Assert.assertEquals("(Ljava/lang/String;)V", invoke.desc); var handle = invoke.bsm; Assert.assertEquals(Type.getInternalName(InvokeDynamicNodeTester.class), handle.getOwner()); Assert.assertEquals("testBootstrap", handle.getName()); Assert.assertEquals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", handle.getDesc()); } @Test public void testInvokeDynamicWithWrappedHandle() throws Exception { var invoke = (InvokeDynamicInsnNode) InvokeDynamicNode.invokeDynamic("tux", List.of(WrappedType.from(String.class)), WrappedType.from(void.class), WrappedHandle.getInvokeStaticHandle(InvokeDynamicNodeTester.class.getMethod("testBootstrap", MethodHandles.Lookup.class, String.class, MethodType.class)), Collections.emptyList()).getNode(); Assert.assertEquals("tux", invoke.name); Assert.assertEquals("(Ljava/lang/String;)V", invoke.desc); var handle = invoke.bsm; Assert.assertEquals(Type.getInternalName(InvokeDynamicNodeTester.class), handle.getOwner()); Assert.assertEquals("testBootstrap", handle.getName()); Assert.assertEquals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", handle.getDesc()); } public static CallSite testBootstrap(MethodHandles.Lookup lookup, String name, MethodType methodType) { return null; } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/InvokeNodeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodInsnNode; import xyz.itzsomebody.codegen.WrappedType; import java.nio.charset.Charset; import java.util.Collections; import java.util.List; public class InvokeNodeTester { @Test public void testInvokeStatic() { var invokeStatic = (MethodInsnNode) InvokeNode.invokeStatic(WrappedType.from(String.class), "valueOf", List.of(WrappedType.from(int.class)), WrappedType.from(String.class)).getNode(); Assert.assertEquals(Opcodes.INVOKESTATIC, invokeStatic.getOpcode()); Assert.assertEquals("java/lang/String", invokeStatic.owner); Assert.assertEquals("valueOf", invokeStatic.name); Assert.assertEquals("(I)Ljava/lang/String;", invokeStatic.desc); } @Test public void testInvokeVirtual() { var invokeVirtual = (MethodInsnNode) InvokeNode.invokeVirtual(WrappedType.from(String.class), "hashCode", Collections.emptyList(), WrappedType.from(int.class)).getNode(); Assert.assertEquals(Opcodes.INVOKEVIRTUAL, invokeVirtual.getOpcode()); Assert.assertEquals("java/lang/String", invokeVirtual.owner); Assert.assertEquals("hashCode", invokeVirtual.name); Assert.assertEquals("()I", invokeVirtual.desc); } @Test public void testInvokeInterface() { var invokeInterface = (MethodInsnNode) InvokeNode.invokeInterface(WrappedType.from(CharSequence.class), "length", Collections.emptyList(), WrappedType.from(int.class)).getNode(); Assert.assertEquals(Opcodes.INVOKEINTERFACE, invokeInterface.getOpcode()); Assert.assertEquals("java/lang/CharSequence", invokeInterface.owner); Assert.assertEquals("length", invokeInterface.name); Assert.assertEquals("()I", invokeInterface.desc); } @Test public void testInvokeSpecials() { var invokeSpecial = (MethodInsnNode) InvokeNode.invokeSpecial(WrappedType.from(String.class), "valueOf", List.of(WrappedType.from(int.class)), WrappedType.from(String.class)).getNode(); Assert.assertEquals(Opcodes.INVOKESPECIAL, invokeSpecial.getOpcode()); Assert.assertEquals("java/lang/String", invokeSpecial.owner); Assert.assertEquals("valueOf", invokeSpecial.name); Assert.assertEquals("(I)Ljava/lang/String;", invokeSpecial.desc); } @Test public void testInvokeConstructor() { var invokeConstructor = (MethodInsnNode) InvokeNode.invokeConstructor(WrappedType.from(String.class), List.of(WrappedType.from(byte[].class), WrappedType.from(Charset.class))).getNode(); Assert.assertEquals(Opcodes.INVOKESPECIAL, invokeConstructor.getOpcode()); Assert.assertEquals("java/lang/String", invokeConstructor.owner); Assert.assertEquals("", invokeConstructor.name); Assert.assertEquals("([BLjava/nio/charset/Charset;)V", invokeConstructor.desc); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/NewArrayNodeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; public class NewArrayNodeTester { @Test public void testPrimitiveArrayType() { Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(boolean.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_BOOLEAN, ((IntInsnNode) new NewArrayNode(WrappedType.from(boolean.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(char.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_CHAR, ((IntInsnNode) new NewArrayNode(WrappedType.from(char.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(byte.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_BYTE, ((IntInsnNode) new NewArrayNode(WrappedType.from(byte.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(short.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_SHORT, ((IntInsnNode) new NewArrayNode(WrappedType.from(short.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(int.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_INT, ((IntInsnNode) new NewArrayNode(WrappedType.from(int.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(long.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_LONG, ((IntInsnNode) new NewArrayNode(WrappedType.from(long.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(float.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_FLOAT, ((IntInsnNode) new NewArrayNode(WrappedType.from(float.class)).getNode()).operand); Assert.assertEquals(Opcodes.NEWARRAY, new NewArrayNode(WrappedType.from(double.class)).getNode().getOpcode()); Assert.assertEquals(Opcodes.T_DOUBLE, ((IntInsnNode) new NewArrayNode(WrappedType.from(double.class)).getNode()).operand); } @Test public void testNonPrimitiveArrayType() { Assert.assertEquals(Opcodes.ANEWARRAY, new NewArrayNode(WrappedType.from(String.class)).getNode().getOpcode()); Assert.assertEquals("java/lang/String", ((TypeInsnNode) new NewArrayNode(WrappedType.from(String.class)).getNode()).desc); Assert.assertEquals(Opcodes.ANEWARRAY, new NewArrayNode(WrappedType.from(Integer.class)).getNode().getOpcode()); Assert.assertEquals("java/lang/Integer", ((TypeInsnNode) new NewArrayNode(WrappedType.from(Integer.class)).getNode()).desc); } } ================================================ FILE: xyz.itzsomebody.codegen/src/test/java/xyz/itzsomebody/codegen/instructions/TypeNodeTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.codegen.instructions; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.TypeInsnNode; import xyz.itzsomebody.codegen.WrappedType; public class TypeNodeTester { @Test public void testNewInstanceForCorrectOpcode() { Assert.assertEquals(Opcodes.NEW, TypeNode.newInstance(WrappedType.from(String.class)).getNode().getOpcode()); } @Test public void testNewInstanceForValidType() { Assert.assertEquals("java/lang/String", ((TypeInsnNode) TypeNode.newInstance(WrappedType.from(String.class)).getNode()).desc); } } ================================================ FILE: xyz.itzsomebody.commons/README.md ================================================ # Commons TODO: put analyzers and instruction matcher here ================================================ FILE: xyz.itzsomebody.commons/build.gradle ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ plugins { id 'java' } sourceCompatibility = javaVer dependencies { implementation annotations implementation asm implementation asmTree implementation asmAnalysis testImplementation junit } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/InsnListModifier.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons; import org.jetbrains.annotations.NotNull; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodNode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class allows for easy modifications of {@link org.objectweb.asm.tree.InsnList}s. This is identical in idea to * the "InstructionModifier" in java-deobfuscator. The idea of this modifier is to make it easier to modify instruction * lists while iterating over them. */ public class InsnListModifier { private final List appends = new ArrayList<>(); private final List prepends = new ArrayList<>(); private final Map inserts = new HashMap<>(); private final Map insertBefores = new HashMap<>(); private final Map replacements = new HashMap<>(); private final List removals = new ArrayList<>(); public InsnListModifier append(InsnList insns) { appends.add(insns); return this; } public InsnListModifier append(@NotNull AbstractInsnNode... insns) { var list = new InsnList(); List.of(insns).forEach(list::add); appends.add(list); return this; } public InsnListModifier prepend(InsnList insns) { prepends.add(insns); return this; } public InsnListModifier prepend(@NotNull AbstractInsnNode... insns) { var list = new InsnList(); List.of(insns).forEach(list::add); prepends.add(list); return this; } public InsnListModifier insert(AbstractInsnNode previous, InsnList insns) { inserts.put(previous, insns); return this; } public InsnListModifier insert(AbstractInsnNode previous, @NotNull AbstractInsnNode... insns) { var list = new InsnList(); List.of(insns).forEach(list::add); inserts.put(previous, list); return this; } public InsnListModifier insertBefore(AbstractInsnNode next, InsnList insns) { insertBefores.put(next, insns); return this; } public InsnListModifier insertBefore(AbstractInsnNode next, @NotNull AbstractInsnNode... insns) { var list = new InsnList(); List.of(insns).forEach(list::add); insertBefores.put(next, list); return this; } public InsnListModifier replace(AbstractInsnNode old, InsnList replacement) { replacements.put(old, replacement); return this; } public InsnListModifier replace(AbstractInsnNode old, @NotNull AbstractInsnNode... insns) { var list = new InsnList(); List.of(insns).forEach(list::add); replacements.put(old, list); return this; } public InsnListModifier remove(AbstractInsnNode insn) { removals.add(insn); return this; } public InsnListModifier remove(@NotNull AbstractInsnNode... insns) { List.of(insns).forEach(this::remove); return this; } public InsnListModifier remove(Iterable iterable) { iterable.forEach(this::remove); return this; } public void apply(InsnList insns) { appends.forEach(insns::add); prepends.forEach(insns::insert); inserts.forEach(insns::insert); insertBefores.forEach(insns::insertBefore); replacements.forEach((old, replacement) -> { insns.insert(old, replacement); insns.remove(old); }); removals.forEach(insns::remove); } public void apply(MethodNode node) { apply(node.instructions); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/MaxLocalsUpdater.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; /** * Determines the numbers of locals slots being used by a method based on the variable instructions within the method. * * @author itzsomebody */ public class MaxLocalsUpdater { private final MethodNode methodNode; private MaxLocalsUpdater(MethodNode methodNode) { this.methodNode = methodNode; } private int computeMaxs() { int size = 0; if ((methodNode.access & Opcodes.ACC_STATIC) == 0) { size += 1; // Non-static implicitly declares variable 0 as "this" } for (var type : Type.getArgumentTypes(methodNode.desc)) { size += type.getSize(); } var visitor = new MaxLocalsVisitor(size); methodNode.accept(visitor); return visitor.getSize(); // Quality code /s } public static void update(MethodNode methodNode) { methodNode.visitMaxs(methodNode.maxStack, new MaxLocalsUpdater(methodNode).computeMaxs()); } class MaxLocalsVisitor extends MethodVisitor { private int size; public MaxLocalsVisitor(int initialSize) { super(/* latest api */ Opcodes.ASM9, null); this.size = initialSize; } @Override public void visitVarInsn(int opcode, int var) { if (var >= size) { size = var + 1; if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { size += 1; } } } @Override public void visitIincInsn(int var, int increment) { if (var >= size) { size = var + 1; } } public int getSize() { return size; } } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/analysis/callgraph/CallGraphAnalyzer.java ================================================ package xyz.itzsomebody.commons.analysis.callgraph; public class CallGraphAnalyzer { // TODO } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/analysis/cfg/CFGAnalyzer.java ================================================ package xyz.itzsomebody.commons.analysis.cfg; public class CFGAnalyzer { // TODO } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/analysis/frame/FrameAnalyzer.java ================================================ package xyz.itzsomebody.commons.analysis.frame; public class FrameAnalyzer { // tODO } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/InstructionMatcher.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher; import org.objectweb.asm.tree.AbstractInsnNode; import java.util.ArrayList; import java.util.List; public class InstructionMatcher { private final InstructionPattern pattern; private final AbstractInsnNode start; private final List> captured = new ArrayList<>(); public InstructionMatcher(InstructionPattern pattern, AbstractInsnNode start) { this.pattern = pattern; this.start = start; } public boolean matches() { var rules = pattern.getRules(); if (rules.size() == 0) { return false; } var current = start; ArrayList possibleMatch = new ArrayList<>(); for (var rule : rules) { if (current == null || !rule.matches(this, current)) { return false; } possibleMatch.add(current); current = current.getNext(); } if (current != null) { return false; } captured.add(possibleMatch); return true; } public boolean find() { // This is a good example of why you shouldn't let me algorithmic programming var rules = pattern.getRules(); if (rules.size() == 0) { return false; } var initialSize = captured.size(); ArrayList possibleMatch = new ArrayList<>(); var current = start; int currentRuleIndex = 0; while (current != null) { if (rules.get(currentRuleIndex).matches(this, current)) { possibleMatch.add(current); if (++currentRuleIndex == rules.size()) { captured.add(possibleMatch); currentRuleIndex = 0; possibleMatch = new ArrayList<>(); } } else { currentRuleIndex = 0; possibleMatch.clear(); } current = current.getNext(); } return captured.size() - initialSize != 0; } public List getCaptured(int which) { return captured.get(which); } public List> getAllCaptured() { return captured; } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/InstructionPattern.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher; import org.jetbrains.annotations.NotNull; import org.objectweb.asm.tree.AbstractInsnNode; import xyz.itzsomebody.commons.matcher.rules.InstructionRule; import java.util.List; public class InstructionPattern { private final List rules; public InstructionPattern(@NotNull InstructionRule... rules) { this.rules = List.of(rules); } public List getRules() { return rules; } public InstructionMatcher matcher(AbstractInsnNode start) { return new InstructionMatcher(this, start); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/AccessFieldRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import xyz.itzsomebody.commons.matcher.InstructionMatcher; import java.util.function.Function; public class AccessFieldRule extends OpcodeRule { private final int opcode; private final String owner; private final String name; private final String description; public AccessFieldRule(Function rule, int opcode, String owner, String name, String description) { super(rule, Opcodes.GETFIELD, Opcodes.GETSTATIC, Opcodes.PUTFIELD, Opcodes.PUTSTATIC); this.opcode = opcode; this.owner = owner; this.name = name; this.description = description; } public AccessFieldRule(int opcode, String owner, String name, String description) { super(null, Opcodes.GETFIELD, Opcodes.GETSTATIC, Opcodes.PUTFIELD, Opcodes.PUTSTATIC); this.opcode = opcode; this.owner = owner; this.name = name; this.description = description; } @Override public boolean matches(InstructionMatcher matcher, AbstractInsnNode current) { if (current.getOpcode() == opcode && current instanceof FieldInsnNode) { var casted = (FieldInsnNode) current; return (owner == null || owner.equals(casted.owner)) && (name == null || name.equals(casted.name)) && (description == null || description.equals(casted.desc)); } return false; } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/DoubleConstRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.LdcInsnNode; public class DoubleConstRule extends OpcodeRule { public DoubleConstRule() { super(current -> { if (current instanceof LdcInsnNode && !(((LdcInsnNode) current).cst instanceof Double)) { return false; } return true; }, Opcodes.DCONST_0, Opcodes.DCONST_1, Opcodes.LDC ); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/FloatConstRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.LdcInsnNode; public class FloatConstRule extends OpcodeRule { public FloatConstRule() { super(current -> { if (current instanceof LdcInsnNode && !(((LdcInsnNode) current).cst instanceof Float)) { return false; } return true; }, Opcodes.FCONST_0, Opcodes.FCONST_1, Opcodes.FCONST_2, Opcodes.LDC ); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/InstructionRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.tree.AbstractInsnNode; import xyz.itzsomebody.commons.matcher.InstructionMatcher; public interface InstructionRule { boolean matches(InstructionMatcher matcher, AbstractInsnNode current); } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/IntConstRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.LdcInsnNode; public class IntConstRule extends OpcodeRule { public IntConstRule() { super(current -> { if (current instanceof LdcInsnNode && !(((LdcInsnNode) current).cst instanceof Integer)) { return false; } return true; }, Opcodes.ICONST_M1, Opcodes.ICONST_0, Opcodes.ICONST_1, Opcodes.ICONST_2, Opcodes.ICONST_3, Opcodes.ICONST_4, Opcodes.ICONST_5, Opcodes.BIPUSH, Opcodes.SIPUSH, Opcodes.LDC ); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/InvocationRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import xyz.itzsomebody.commons.matcher.InstructionMatcher; import java.util.function.Function; public class InvocationRule extends OpcodeRule { private final int opcode; private final String owner; private final String name; private final String description; public InvocationRule(Function rule, int opcode, String owner, String name, String description) { super(rule, Opcodes.INVOKEVIRTUAL, Opcodes.INVOKESPECIAL, Opcodes.INVOKESTATIC, Opcodes.INVOKEINTERFACE); this.opcode = opcode; this.owner = owner; this.name = name; this.description = description; } public InvocationRule(int opcode, String owner, String name, String description) { super(null, Opcodes.INVOKEVIRTUAL, Opcodes.INVOKESPECIAL, Opcodes.INVOKESTATIC, Opcodes.INVOKEINTERFACE); this.opcode = opcode; this.owner = owner; this.name = name; this.description = description; } @Override public boolean matches(InstructionMatcher matcher, AbstractInsnNode current) { if (current.getOpcode() == opcode && current instanceof MethodInsnNode) { var casted = (MethodInsnNode) current; return (owner == null || owner.equals(casted.owner)) && (name == null || name.equals(casted.name)) && (description == null || description.equals(casted.desc)); } return false; } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/LongConstRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.LdcInsnNode; public class LongConstRule extends OpcodeRule { public LongConstRule() { super(current -> { if (current instanceof LdcInsnNode && !(((LdcInsnNode) current).cst instanceof Long)) { return false; } return true; }, Opcodes.LCONST_0, Opcodes.LCONST_1, Opcodes.LDC ); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/OpcodeRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.tree.AbstractInsnNode; import xyz.itzsomebody.commons.matcher.InstructionMatcher; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; public class OpcodeRule implements InstructionRule { private final Function rule; private final List wantedOpcodes; public OpcodeRule(Function rule, int... opcodes) { this.rule = rule; this.wantedOpcodes = Arrays.stream(opcodes).boxed().collect(Collectors.toList()); } public OpcodeRule(int... opcodes) { this.rule = null; this.wantedOpcodes = Arrays.stream(opcodes).boxed().collect(Collectors.toList()); } @Override public boolean matches(InstructionMatcher matcher, AbstractInsnNode current) { return wantedOpcodes.contains(current.getOpcode()) && (rule == null || rule.apply(current)); } } ================================================ FILE: xyz.itzsomebody.commons/src/main/java/xyz/itzsomebody/commons/matcher/rules/WildcardRule.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.objectweb.asm.tree.AbstractInsnNode; import xyz.itzsomebody.commons.matcher.InstructionMatcher; public class WildcardRule extends OpcodeRule { public WildcardRule(){ super(null); } @Override public boolean matches(InstructionMatcher matcher, AbstractInsnNode current) { return true; } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/InsnListModifierTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import java.util.stream.IntStream; public class InsnListModifierTester { @Test public void testAppending() { var insns = new InsnList(); var addMe = new InsnList(); addMe.add(new InsnNode(Opcodes.ACONST_NULL)); addMe.add(new InsnNode(Opcodes.ARETURN)); var modifier = new InsnListModifier(); modifier.append(addMe); modifier.apply(insns); IntStream.range(0, addMe.size()).forEach(i -> Assert.assertEquals(addMe.get(i), insns.get(i))); } @Test public void testPrepending() { var insns = new InsnList(); insns.add(new InsnNode(Opcodes.ICONST_1)); insns.add(new InsnNode(Opcodes.POP)); var addMe = new InsnList(); addMe.add(new InsnNode(Opcodes.ACONST_NULL)); addMe.add(new InsnNode(Opcodes.ARETURN)); var modifier = new InsnListModifier(); modifier.prepend(addMe); modifier.apply(insns); IntStream.range(0, addMe.size()).forEach(i -> Assert.assertEquals(addMe.get(i), insns.get(i))); } @Test public void testInsertion() { var insns = new InsnList(); insns.add(new InsnNode(Opcodes.ICONST_1)); insns.add(new InsnNode(Opcodes.POP)); var addMe = new InsnList(); addMe.add(new InsnNode(Opcodes.ACONST_NULL)); addMe.add(new InsnNode(Opcodes.ARETURN)); var modifier = new InsnListModifier(); modifier.insert(insns.getLast(), addMe); modifier.apply(insns); insns.remove(insns.getFirst()); insns.remove(insns.getFirst()); IntStream.range(0, addMe.size()).forEach(i -> Assert.assertEquals(addMe.get(i), insns.get(i))); } @Test public void testInsertionBefore() { var insns = new InsnList(); insns.add(new InsnNode(Opcodes.ACONST_NULL)); insns.add(new InsnNode(Opcodes.ARETURN)); var addMe = new InsnList(); addMe.add(new InsnNode(Opcodes.ICONST_1)); addMe.add(new InsnNode(Opcodes.POP)); var modifier = new InsnListModifier(); modifier.insertBefore(insns.getFirst(), addMe); modifier.apply(insns); insns.remove(insns.getLast()); insns.remove(insns.getLast()); IntStream.range(0, addMe.size()).forEach(i -> Assert.assertEquals(addMe.get(i), insns.get(i))); } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/MaxLocalsUpdaterTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; public class MaxLocalsUpdaterTester { @Test public void testParameterSizeEvaluation() { var node = new MethodNode(); node.desc = "(IIIJD)V"; node.access = Opcodes.ACC_STATIC; MaxLocalsUpdater.update(node); Assert.assertEquals(1 + 1 + 1 + 2 + 2, node.maxLocals); } @Test public void testEvaluationByBytecodeStatic1() { var node = new MethodNode(); node.desc = "(IIIJD)V"; node.access = Opcodes.ACC_STATIC; node.instructions.add(new InsnNode(Opcodes.ICONST_0)); node.instructions.add(new VarInsnNode(Opcodes.ISTORE, 69)); MaxLocalsUpdater.update(node); Assert.assertEquals(69 + 1, node.maxLocals); } @Test public void testEvaluationByBytecodeStatic2() { var node = new MethodNode(); node.desc = "(IIIJD)V"; node.access = Opcodes.ACC_STATIC; node.instructions.add(new InsnNode(Opcodes.LCONST_0)); node.instructions.add(new VarInsnNode(Opcodes.LSTORE, 69)); MaxLocalsUpdater.update(node); Assert.assertEquals(69 + 2, node.maxLocals); } @Test public void testEvaluationByBytecodeVirtual1() { var node = new MethodNode(); node.desc = "(IIIJD)V"; MaxLocalsUpdater.update(node); Assert.assertEquals(1 + 1 + 1 + 1 + 2 + 2, node.maxLocals); } @Test public void testEvaluationByBytecodeVirtual2() { var node = new MethodNode(); node.desc = "(IIIJD)V"; node.instructions.add(new InsnNode(Opcodes.FCONST_0)); node.instructions.add(new VarInsnNode(Opcodes.FSTORE, 69)); MaxLocalsUpdater.update(node); Assert.assertEquals(69 + 1, node.maxLocals); } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/TestingUtils.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; public class TestingUtils { public static AbstractInsnNode loadInt(int i) { if (i >= -1 && i <= 5) { return new InsnNode(i + 3); } else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) { return new IntInsnNode(Opcodes.BIPUSH, i); } else if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) { return new IntInsnNode(Opcodes.SIPUSH, i); } else { return new LdcInsnNode(i); } } public static AbstractInsnNode loadLong(long j) { if (j == 0L || j == 1L) { return new InsnNode((int) j + 9); } else { return new LdcInsnNode(j); } } public static AbstractInsnNode loadFloat(float f) { if (f == 0F || f == 1F || f == 2F) { return new InsnNode((int) f + 11); } else { return new LdcInsnNode(f); } } public static AbstractInsnNode loadDouble(double d) { if (d == 0D || d == 1D) { return new InsnNode((int) d + 14); } else { return new LdcInsnNode(d); } } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/InstructionMatcherTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import xyz.itzsomebody.commons.matcher.rules.InvocationRule; import xyz.itzsomebody.commons.matcher.rules.OpcodeRule; import java.nio.charset.Charset; public class InstructionMatcherTester { @Test public void testMatchMethodInvocationAndArgs() { var insns = new InsnList(); insns.add(new LdcInsnNode("tucks")); insns.add(new LdcInsnNode("tux")); insns.add(new InsnNode(Opcodes.ACONST_NULL)); insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "getBytes", Type.getInternalName(Charset.class), false)); var pattern = new InstructionPattern( new OpcodeRule((node) -> node instanceof LdcInsnNode && ((LdcInsnNode) node).cst.equals("tux"), Opcodes.LDC), new OpcodeRule(Opcodes.ACONST_NULL), new InvocationRule(Opcodes.INVOKEVIRTUAL, "java/lang/String", "getBytes", Type.getInternalName(Charset.class)) ); var matcher = pattern.matcher(insns.getFirst()); Assert.assertFalse(matcher.matches()); Assert.assertTrue(matcher.find()); var captured = matcher.getCaptured(0); insns.remove(insns.getFirst()); for (var i = 0; i < insns.size(); i++) { Assert.assertEquals(insns.get(i), captured.get(i)); } } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/rules/AccessFieldRuleTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.FieldInsnNode; import xyz.itzsomebody.commons.matcher.InstructionPattern; public class AccessFieldRuleTester { @Test public void testMatch() { var pattern = new InstructionPattern(new AccessFieldRule(Opcodes.GETSTATIC, null, null, "I")); var matcher = pattern.matcher(new FieldInsnNode(Opcodes.GETSTATIC, "tucks/Tux", "tucks", "I")); Assert.assertTrue(matcher.matches()); Assert.assertTrue(matcher.find()); } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/rules/DoubleConstRuleTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.junit.Assert; import org.junit.Test; import xyz.itzsomebody.commons.TestingUtils; import xyz.itzsomebody.commons.matcher.InstructionPattern; import java.util.concurrent.ThreadLocalRandom; public class DoubleConstRuleTester { @Test public void testMatch() { var examples = new double[]{ 0D, 1D, ThreadLocalRandom.current().nextDouble() }; for (var example : examples) { var pattern = new InstructionPattern(new DoubleConstRule()); var matcher = pattern.matcher(TestingUtils.loadDouble(example)); Assert.assertTrue(matcher.matches()); Assert.assertTrue(matcher.find()); } } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/rules/FloatConstRuleTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.junit.Assert; import org.junit.Test; import xyz.itzsomebody.commons.TestingUtils; import xyz.itzsomebody.commons.matcher.InstructionPattern; import java.util.concurrent.ThreadLocalRandom; public class FloatConstRuleTester { @Test public void testMatch() { var examples = new float[]{ 0F, 1F, 2F, ThreadLocalRandom.current().nextFloat() }; for (var example : examples) { var pattern = new InstructionPattern(new FloatConstRule()); var matcher = pattern.matcher(TestingUtils.loadFloat(example)); Assert.assertTrue(matcher.matches()); Assert.assertTrue(matcher.find()); } } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/rules/IntConstRuleTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.junit.Assert; import org.junit.Test; import xyz.itzsomebody.commons.TestingUtils; import xyz.itzsomebody.commons.matcher.InstructionPattern; import java.util.concurrent.ThreadLocalRandom; public class IntConstRuleTester { @Test public void testMatch() { var examples = new int[]{ -1, 0, 1, 2, 3, 4, 5, ThreadLocalRandom.current().nextInt(5, Byte.MAX_VALUE), ThreadLocalRandom.current().nextInt(Byte.MAX_VALUE + 1, Short.MAX_VALUE), ThreadLocalRandom.current().nextInt(Short.MAX_VALUE + 1, Integer.MAX_VALUE) }; for (var example : examples) { var pattern = new InstructionPattern(new IntConstRule()); var matcher = pattern.matcher(TestingUtils.loadInt(example)); Assert.assertTrue(matcher.matches()); Assert.assertTrue(matcher.find()); } } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/rules/InvocationRuleTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.junit.Assert; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodInsnNode; import xyz.itzsomebody.commons.matcher.InstructionPattern; public class InvocationRuleTester { @Test public void testMatch() { var pattern = new InstructionPattern(new InvocationRule(Opcodes.INVOKESTATIC, null, null, "()I")); var matcher = pattern.matcher(new MethodInsnNode(Opcodes.INVOKESTATIC, "tucks/Tux", "tucks", "()I")); Assert.assertTrue(matcher.matches()); Assert.assertTrue(matcher.find()); } } ================================================ FILE: xyz.itzsomebody.commons/src/test/java/xyz/itzsomebody/commons/matcher/rules/LongConstRuleTester.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.commons.matcher.rules; import org.junit.Assert; import org.junit.Test; import xyz.itzsomebody.commons.TestingUtils; import xyz.itzsomebody.commons.matcher.InstructionPattern; import java.util.concurrent.ThreadLocalRandom; public class LongConstRuleTester { @Test public void testMatch() { var examples = new long[]{ 0L, 1L, ThreadLocalRandom.current().nextLong() }; for (var example : examples) { var pattern = new InstructionPattern(new LongConstRule()); var matcher = pattern.matcher(TestingUtils.loadLong(example)); Assert.assertTrue(matcher.matches()); Assert.assertTrue(matcher.find()); } } } ================================================ FILE: xyz.itzsomebody.radon/build.gradle ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ import org.apache.tools.ant.filters.ReplaceTokens plugins { id 'com.github.johnrengelman.shadow' id 'java' } // So people stop asking why 'gradle build' doesn't work. Lmao I'm lazy build.dependsOn 'shadowJar' sourceCompatibility = javaVer // Main class def mainClass = 'xyz.itzsomebody.radon.RadonMain' // Function to grab the git commit hash of HEAD def getCommitHash = { -> def stdout = new ByteArrayOutputStream() exec { commandLine 'git', 'rev-parse', 'HEAD' standardOutput = stdout } return stdout.toString().trim() } // Search for and replace project version and commit hash placeholders in the source code task processSource(type: Sync) { from sourceSets.main.java filter(ReplaceTokens, tokens: [VERSION: version, COMMITHASH: getCommitHash()]) into "$buildDir/src" } compileJava { source = processSource.outputs } // Creates a fat jar shadowJar() { archiveClassifier.set(null) // Relocate lib classes relocate 'org.objectweb.asm', 'xyz.itzsomebody.radon.lib.org.objectweb.asm' relocate 'com.fasterxml.jackson', 'xyz.itzsomebody.radon.lib.com.fasterxml.jackson' exclude 'module-info.class' manifest { attributes 'Main-Class': mainClass } } dependencies { implementation project(':xyz.itzsomebody.codegen') implementation project(':xyz.itzsomebody.commons') implementation annotations implementation jackson implementation asm implementation asmAnalysis implementation asmCommons implementation asmTree implementation asmUtil testImplementation junit } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/Radon.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon; import xyz.itzsomebody.radon.config.ObfConfig; import xyz.itzsomebody.radon.exceptions.MissingClassException; import xyz.itzsomebody.radon.exceptions.MissingResourceException; import xyz.itzsomebody.radon.exclusions.ExclusionManager; import xyz.itzsomebody.radon.utils.JarLoader; import xyz.itzsomebody.radon.utils.JarWriter; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; public class Radon { private static Radon radon; private final ExclusionManager exclusionManager; public final ObfConfig config; private Map classes; private Map classpath; private Map resources; public Radon(ObfConfig config) { this.config = config; this.exclusionManager = config.exclusions; radon = this; } public void run() { // ========================== Load input & libs var loader = new JarLoader(); loader.loadAsInput(config.input); // Load input this.config.libraries.forEach(loader::loadAsLib); // Load libs this.classes = loader.getClasses(); this.classpath = loader.getClasspath(); this.resources = loader.getResources(); // ========================== Transformation var transformers = config.transformers; // Run 'em all // re nonNull: check fix-me in TransformerDeserializer transformers.stream().filter(Objects::nonNull).forEach(transformer -> { RadonLogger.info("[Transformers] Executing: " + transformer.getName() + " (" + transformer.getConfigName() + ")"); transformer.init(this); // Quality way of measuring execution time /sarcasm long before = System.currentTimeMillis(); transformer.transform(); long after = System.currentTimeMillis(); RadonLogger.info("[Transformers] Finished executing: " + transformer.getName() + " [" + (after - before) + "ms]"); }); // ========================== Write output var writer = new JarWriter(); writer.write(config.output); } private void buildHierarchy(ClassWrapper wrapper, ClassWrapper sub, Set visited) { if (visited.add(wrapper.getName())) { if (wrapper.getSuperName() != null) { var superParent = getClasspathWrapper(wrapper.getSuperName()); wrapper.getParents().add(superParent); buildHierarchy(superParent, wrapper, visited); } if (wrapper.getInterfaceNames() != null) { wrapper.getInterfaceNames().forEach(interfaceName -> { var interfaceParent = getClasspathWrapper(interfaceName); wrapper.getParents().add(interfaceParent); buildHierarchy(interfaceParent, wrapper, visited); }); } } if (sub != null) { wrapper.getChildren().add(sub); } } public void buildHierarchyGraph() { HashSet visited = new HashSet<>(); classes.values().forEach(wrapper -> buildHierarchy(wrapper, null, visited)); } public static Radon getInstance() { return radon; } public ClassWrapper getClassWrapper(String name) { var wrapper = classes.get(name); if (wrapper == null) { throw MissingClassException.forInputClass(name); } return wrapper; } public Map getClasses() { return classes; } public void setClasses(Map classes) { this.classes = classes; } public ClassWrapper getClasspathWrapper(String name) { var wrapper = classpath.get(name); if (wrapper == null) { throw MissingClassException.forLibraryClass(name); } return wrapper; } public Map getClasspath() { return classpath; } public void setClasspath(Map classpath) { this.classpath = classpath; } public byte[] getResource(String name) { var resource = resources.get(name); if (resource == null) { throw new MissingResourceException(name); } return resource; } public void setResources(Map resources) { this.resources = resources; } public Map getResources() { return resources; } public ExclusionManager getExclusionManager() { return exclusionManager; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/RadonConstants.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon; /** * Various constants used throughout the obfuscator. * * @author itzsomebody */ public interface RadonConstants { String VERSION = "@VERSION@"; String GIT_HASH = "@COMMITHASH@"; String LOG_TIMESTAMP_FORMAT = "dd/MM/yyyy-hh:mm:ss"; String DEFAULT_ZIP_COMMENT = "Radon is a free and open-source Java bytecode obfuscator released under GPLv3\nhttps://github.com/ItzSomebody/radon"; boolean VERBOSE = true; // Because spamming the console is fun } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/RadonMain.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon; import xyz.itzsomebody.radon.cli.CmdArgsParser; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.config.ObfConfig; import xyz.itzsomebody.radon.exceptions.FatalRadonException; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import xyz.itzsomebody.radon.transformers.misc.Watermarker; import xyz.itzsomebody.radon.utils.IOUtils; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.zip.ZipFile; /** * Entry point for the Radon Java bytecode obfuscator. * * @author itzsomebody */ public class RadonMain { /** * Underlying implementation of {@link RadonMain#bootstrap(boolean)}. * * @param cliMode Determines if the obfuscator should initialize {@link CmdArgsParser}. */ @SuppressWarnings("SameParameterValue") private static void bootstrap0(final boolean cliMode) { // RadonLogger try { // Throws from static initializer if some random thing should go rip RadonLogger.info("Finished setting up RadonLogger"); } catch (Throwable t) { System.out.println("Some random error happened while bootstrapping logger D:"); t.printStackTrace(System.out); System.exit(-1); } // CLI stuff // For console-application usage if (cliMode) { CmdArgsParser.registerSwitch("help", 0); CmdArgsParser.registerSwitch("license", 0); // not that anybody cares abt this one CmdArgsParser.registerSwitch("config", 1); CmdArgsParser.registerSwitch("extract", 2); RadonLogger.info("Finished setting up command line parser"); } } /** * Initializes the {@link RadonLogger}. Also initializes {@link CmdArgsParser} if the obfuscator is being run * from the console. * * @param cliMode Determines if the obfuscator should initialize {@link CmdArgsParser}. */ public static void bootstrap(boolean cliMode) { bootstrap0(cliMode); RadonLogger.info("Finished bootstrap phase"); RadonLogger.info("Radon: A free and open-source experimental JVM bytecode obfuscator"); RadonLogger.info(String.format("Version: %s (commit hash: %s)", RadonConstants.VERSION, RadonConstants.GIT_HASH)); RadonLogger.info("Repository: https://github.com/ItzSomebody/radon"); } private static int cliThing(String[] args) { // Parse all the args off the command line var parser = new CmdArgsParser(); parser.parse(args); // Do stuff based on whatever was thrown in if (parser.containsSwitch("help")) { var programName = new File(RadonMain.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getName(); RadonLogger.info(String.format("Extractor: %5s java -jar %s --extract example.jar", "", programName)); RadonLogger.info(String.format("CLI Usage: %5s java -jar %s --config example.yml", "", programName)); RadonLogger.info(String.format("Help Menu: %5s java -jar %s --config example.yml", "", programName)); RadonLogger.info(String.format("License: %5s java -jar %s --config example.yml", "", programName)); } else if (parser.containsSwitch("license")) { try { RadonLogger.info(new String(IOUtils.toByteArray(RadonMain.class.getResourceAsStream("/radon-license.txt")), StandardCharsets.UTF_8)); } catch (IOException ioe) { RadonLogger.severe("Unable to load the license file"); ioe.printStackTrace(System.out); } } else if (parser.containsSwitch("config")) { var configPath = parser.getArgsFor("config")[0]; var configFile = new File(configPath); if (!configFile.exists()) { RadonLogger.severe(String.format("Could not find specified config file \"%s\"", configFile.getAbsolutePath())); } if (!configFile.canRead()) { RadonLogger.severe(String.format("Cannot not read specified config file \"%s\"", configFile.getAbsolutePath())); } if (!configFile.isFile()) { RadonLogger.severe(String.format("Specified config file \"%s\" is not a file", configFile.getAbsolutePath())); } ConfigurationParser config; try { config = new ConfigurationParser(new FileInputStream(configFile)); } catch (FileNotFoundException e) { RadonLogger.severe("Unknown IO error happened: " + e.getMessage()); if (RadonConstants.VERBOSE) { e.printStackTrace(); } return -1; } try { var radon = new Radon(config.parseConfig()); radon.run(); } catch (FatalRadonException e) { RadonLogger.severe("A fatal exception was thrown: " + e.getMessage()); if (RadonConstants.VERBOSE) { e.printStackTrace(System.out); } return -1; } catch (PreventableRadonException e) { RadonLogger.severe("A preventable exception was thrown: " + e.getMessage()); if (RadonConstants.VERBOSE) { e.printStackTrace(System.out); } return 1; } catch (Throwable t) { RadonLogger.severe("An unknown error was throw: " + t.getMessage()); if (RadonConstants.VERBOSE) { t.printStackTrace(System.out); } return -1; } } else if (parser.containsSwitch("extract")) { // At this point I was too lazy to write proper code -- I don't think anyone uses this anyways lmao var switchArgs = parser.getArgsFor("extract"); File leaked = new File(switchArgs[0]); if (!leaked.exists()) { RadonLogger.severe("Input file not found"); return -1; } try { var extractor = new Watermarker.Extractor(new ZipFile(leaked), switchArgs[1]); RadonLogger.info(extractor.extractId()); } catch (FatalRadonException e) { RadonLogger.severe("A fatal exception was thrown: " + e.getMessage()); if (RadonConstants.VERBOSE) { e.printStackTrace(System.out); } return -1; } catch (PreventableRadonException e) { RadonLogger.severe("A preventable exception was thrown: " + e.getMessage()); if (RadonConstants.VERBOSE) { e.printStackTrace(System.out); } return 1; } catch (Throwable t) { RadonLogger.severe("An unknown error was throw: " + t.getMessage()); if (RadonConstants.VERBOSE) { t.printStackTrace(System.out); } return -1; } } else { RadonLogger.info("Unknown operation: perhaps try viewing the results of --help?"); } // Thank the Lord RadonLogger.info("Exiting gracefully"); return 0; } /** * Entry point to the obfuscator. */ public static void main(String[] args) { // Bootstrap to init stuffs bootstrap(true); // Run the stuff System.exit(cliThing(args)); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/cli/CmdArgsParser.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.cli; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Stream; public class CmdArgsParser { private final static String[] SWITCH_PREFIXES = {"--", "-", "/"}; private final static Set SWITCHES = new HashSet<>(); private final Map argMap = new HashMap<>(); private String getSwitchIdOrThrow(String arg) { return arg.substring(Stream.of(SWITCH_PREFIXES) .filter(arg::startsWith) .findFirst() .orElseThrow(() -> new PreventableRadonException("Unexpected command argument: \"" + arg + "\"")) .length()); } public void parse(String[] args) { for (var cliArgIndex = 0; cliArgIndex < args.length; cliArgIndex++) { final var switchId = getSwitchIdOrThrow(args[cliArgIndex]); var knownSwitch = false; for (var cmdSwitch : SWITCHES) { if (cmdSwitch.id.equals(switchId)) { String[] switchArgs = new String[cmdSwitch.expectedArgs]; for (var switchArgIndex = 0; switchArgIndex < cmdSwitch.expectedArgs; switchArgIndex++) { try { switchArgs[switchArgIndex] = args[++cliArgIndex]; } catch (ArrayIndexOutOfBoundsException e) { throw new PreventableRadonException(String.format("Command switch \"%s\" expected %d argument(s), got %d instead.", switchId, cmdSwitch.expectedArgs, switchArgIndex )); } } argMap.put(switchId, switchArgs); knownSwitch = true; break; } } if (!knownSwitch) { throw new PreventableRadonException("Unknown command switch: \"" + switchId + "\""); } } } public static void registerSwitch(String id, int expectedArgs) { registerSwitch(new CmdSwitch(id, expectedArgs)); } public static void registerSwitch(CmdSwitch cmdSwitch) { SWITCHES.add(cmdSwitch); } public boolean containsSwitch(String id) { return argMap.containsKey(id); } public String[] getArgsFor(String id) { return argMap.get(id); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/cli/CmdSwitch.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.cli; import java.util.Objects; public class CmdSwitch { public final String id; public final int expectedArgs; public CmdSwitch(String id, int expectedArgs) { this.id = id; this.expectedArgs = expectedArgs; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o instanceof CmdSwitch) { var other = (CmdSwitch) o; return (this.expectedArgs == other.expectedArgs) && (Objects.equals(this.id, other.id)); } return true; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/config/ConfigurationParser.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import xyz.itzsomebody.radon.exclusions.ExclusionManager; import xyz.itzsomebody.radon.transformers.Transformer; import java.io.IOException; import java.io.InputStream; /** * Parser for the config * * @author itzsomebody */ public class ConfigurationParser extends ObjectMapper { private final InputStream configStream; public ConfigurationParser(InputStream configStream) { super(); registerModule(new SimpleModule() .addDeserializer(Transformer.class, new TransformerDeserializer()) .addDeserializer(ExclusionManager.class, new ExclusionsDeserializer()) ); this.configStream = configStream; } public ObfConfig parseConfig() throws IOException { return readValue(configStream, ObfConfig.class); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/config/DictionaryDeserializer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.config; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.dictionaries.DictionaryFactory; import java.io.IOException; public class DictionaryDeserializer extends JsonDeserializer { @Override public Dictionary deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { var dictionaryName = p.readValueAs(String.class); return DictionaryFactory.forName(dictionaryName); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/config/ExclusionsDeserializer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.config; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import xyz.itzsomebody.radon.exclusions.ExclusionManager; import java.io.IOException; import java.util.HashMap; public class ExclusionsDeserializer extends JsonDeserializer { @Override public ExclusionManager deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); var map = new HashMap(); node.fields().forEachRemaining(entry -> map.put(entry.getKey(), entry.getValue().asText())); return new ExclusionManager(map); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/config/ObfConfig.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.config; import com.fasterxml.jackson.annotation.JsonProperty; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.exclusions.ExclusionManager; import xyz.itzsomebody.radon.transformers.Transformer; import java.util.Collections; import java.util.List; import java.util.zip.Deflater; /** * Provides all of the information needed for Radon to do its job. * * @author itzsomebody */ public class ObfConfig { @JsonProperty("input") public String input; @JsonProperty("output") public String output; @JsonProperty("libraries") public List libraries; @JsonProperty("exclusions") public ExclusionManager exclusions = new ExclusionManager(Collections.emptyMap()); @JsonProperty("transformers") public List transformers; @JsonProperty("use_store") public boolean useStore; @JsonProperty("compression_level") public int compressionLevel = Deflater.BEST_COMPRESSION; @JsonProperty("zip_comment") public String zipComment = RadonConstants.DEFAULT_ZIP_COMMENT; @JsonProperty("verify") public boolean verify; @JsonProperty("fake_duplicate_entries") public int fakeDuplicateEntries; @JsonProperty("corrupt_crcs") public boolean corruptCrcs; @JsonProperty("anti_extraction") public boolean antiExtraction; @JsonProperty("attempt_compute_maxs") public boolean attemptComputeMaxs; } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/config/TransformerDeserializer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.config; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.exceptions.FatalRadonException; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import java.io.IOException; import java.lang.reflect.InvocationTargetException; /** * Deseralizer for transformers * * @author itzsomebody */ public class TransformerDeserializer extends JsonDeserializer { private static Transformer transformerFor(String name) { try { var transformerEnum = Transformers.valueOf(name.toUpperCase()); var clazz = transformerEnum.getTransformerClass(); var cnstr = clazz.getConstructor(); cnstr.setAccessible(true); return cnstr.newInstance(); } catch (IllegalArgumentException e) { throw new PreventableRadonException("Transformer \"" + name + "\" is an unknown transformer"); } catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) { throw new FatalRadonException(e); } catch (InvocationTargetException e) { throw new FatalRadonException(e.getTargetException()); } } @Override public Transformer deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { JsonNode node = jp.getCodec().readTree(jp); var entry = node.fields().next(); var transformer = transformerFor(entry.getKey()); if (entry.getValue().isBoolean()) { if (entry.getValue().asBoolean()) { return transformer; } else { return null; // fixme: don't caboose null } } else { var mapper = new ObjectMapper(new JsonFactory()); mapper.registerModule(new SimpleModule().addDeserializer(Dictionary.class, new DictionaryDeserializer())); return mapper.readerForUpdating(transformer).readValue(entry.getValue()); } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/Dictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries; import xyz.itzsomebody.radon.utils.RandomUtils; public interface Dictionary { String next(); String randomStr(int length); String configName(); Dictionary copy(); // https://en.wikipedia.org/wiki/Bijective_numeration static String toBijectiveBase(char[] charset, int decimal) { var sb = new StringBuilder(); while (decimal-- > 0) { sb.insert(0, charset[decimal % charset.length]); decimal /= charset.length; } return sb.toString(); } static String randomString(char[] charset, int length) { var charsetLength = charset.length; var buf = new char[length]; for (int i = 0; i < length; i++) { buf[i] = charset[RandomUtils.randomInt(charsetLength)]; } return new String(buf); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/DictionaryFactory.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries; import xyz.itzsomebody.radon.dictionaries.defined.*; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.List; public class DictionaryFactory { private static final Dictionary[] DEFINED = { new AlphabeticalDictionary(), new AlphaNumericDictionary(), new RandomUnicodeDictionary(), new SpacesDictionary(), new UnrecognizedDictionary() }; public static Dictionary forName(String name) { return List.of(DEFINED).stream() .filter(dictionary -> name.equalsIgnoreCase(dictionary.configName())) .findFirst() .orElseGet(() -> { RadonLogger.info("Unknown dictionary \"" + name + "\" -- treating as user-defined charset dictionary"); return new CustomCharsetDictionary(name); }); } public static Dictionary defaultDictionary() { return new AlphabeticalDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/defined/AlphaNumericDictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries.defined; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.utils.RandomUtils; public class AlphaNumericDictionary implements Dictionary { private static final char[] CHARSET = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); private int index = 1; @Override public String next() { return Dictionary.toBijectiveBase(CHARSET, index++); } @Override public String randomStr(int length) { return Dictionary.randomString(CHARSET, length); } @Override public String configName() { return "alphanumeric"; } @Override public Dictionary copy() { return new AlphaNumericDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/defined/AlphabeticalDictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries.defined; import xyz.itzsomebody.radon.dictionaries.Dictionary; public class AlphabeticalDictionary implements Dictionary { private static final char[] CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); private int index = 1; @Override public String next() { return Dictionary.toBijectiveBase(CHARSET, index++); } @Override public String randomStr(int length) { return Dictionary.randomString(CHARSET, length); } @Override public String configName() { return "alphabetical"; } @Override public Dictionary copy() { return new AlphabeticalDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/defined/CustomCharsetDictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries.defined; import xyz.itzsomebody.radon.dictionaries.Dictionary; public class CustomCharsetDictionary implements Dictionary { private final char[] charset; private int index = 1; public CustomCharsetDictionary(String charsetString) { charset = charsetString.toCharArray(); } @Override public String next() { return Dictionary.toBijectiveBase(charset, index++); } @Override public String randomStr(int length) { return Dictionary.randomString(charset, length); } @Override public String configName() { // This is intentional return null; } @Override public Dictionary copy() { return new AlphaNumericDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/defined/RandomUnicodeDictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries.defined; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.utils.RandomUtils; public class RandomUnicodeDictionary implements Dictionary { private static final char[] CHARSET = new char[25]; private int index = 1; static { for (int i = 0; i < CHARSET.length; i++) { CHARSET[i] = (char) RandomUtils.randomInt('\u2000', '\uFFFF'); } } @Override public String next() { return Dictionary.toBijectiveBase(CHARSET, index++); } @Override public String randomStr(int length) { return Dictionary.randomString(CHARSET, length); } @Override public String configName() { return "random_unicode"; } @Override public Dictionary copy() { return new RandomUnicodeDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/defined/SpacesDictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries.defined; import xyz.itzsomebody.radon.dictionaries.Dictionary; public class SpacesDictionary implements Dictionary { private static final char[] CHARSET = new char[0xF + 1]; private int index = 1; static { for (int i = 0; i < CHARSET.length; i++) { CHARSET[i] = (char) ('\u2000' + i); } } @Override public String next() { return Dictionary.toBijectiveBase(CHARSET, index++); } @Override public String randomStr(int length) { return Dictionary.randomString(CHARSET, length); } @Override public String configName() { return "spaces"; } @Override public Dictionary copy() { return new SpacesDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/dictionaries/defined/UnrecognizedDictionary.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.dictionaries.defined; import xyz.itzsomebody.radon.dictionaries.Dictionary; public class UnrecognizedDictionary implements Dictionary { private static final char[] CHARSET = new char[33]; private int index = 1; static { for (int i = 0; i < CHARSET.length; i++) { CHARSET[i] = (char) ('\ua6ac' + i); } } @Override public String next() { return Dictionary.toBijectiveBase(CHARSET, index++); } @Override public String randomStr(int length) { return Dictionary.randomString(CHARSET, length); } @Override public String configName() { return "unrecognized"; } @Override public Dictionary copy() { return new UnrecognizedDictionary(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/exceptions/FatalRadonException.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.exceptions; /** * A subclass of {@link RuntimeException} that should only be thrown on non-user-preventable exceptions (e.g. * programmatic or logic errors). * * @author itzsomebody */ public class FatalRadonException extends RuntimeException { public FatalRadonException() { super(); } public FatalRadonException(String msg) { super(msg); } public FatalRadonException(Throwable t) { super(t); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/exceptions/MissingClassException.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.exceptions; /** * Subclass of {@link PreventableRadonException} which is thrown when Radon is unable to find classes that should have * been in either the input JAR or in one of the user-provided libraries in the config. * * @author itzsomebody */ public class MissingClassException extends PreventableRadonException { private MissingClassException(String className, boolean library) { super("Do NOT report this as an issue unless you have ensured the supposedly missing class is actually in at " + "least one of the provided libraries in your config.\n" + String.format( "Could not find \"%s\" in the %s.", className, library ? "classpath" : "input JAR classes")); } public static MissingClassException forInputClass(String className) { return new MissingClassException(className, false); } public static MissingClassException forLibraryClass(String className) { return new MissingClassException(className, true); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/exceptions/MissingResourceException.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.exceptions; public class MissingResourceException extends PreventableRadonException { public MissingResourceException(String resourceName) { super("Do NOT report this as an issue unless you have ensured the supposedly missing resource is actually in" + "the input jar.\n" + String.format("Could not find \"%s\" in the input JAR.", resourceName)); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/exceptions/PreventableRadonException.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.exceptions; /** * A subclass of {@link RuntimeException} that should only be thrown on user-preventable exceptions * (e.g. certain OOM errors). * * @author itzsomebody */ public class PreventableRadonException extends RuntimeException { public PreventableRadonException() { super(); } public PreventableRadonException(String msg) { super(msg); } public PreventableRadonException(Throwable t) { super(t); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/exclusions/Exclusion.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.exclusions; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Exclusion { private final Matcher matcher; private final String rawPattern; private final boolean invert; private final ExclusionType exclusionType; public Exclusion(String pattern) { this(pattern, false); } public Exclusion(String pattern, boolean invert) { this(pattern, ExclusionType.GLOBAL, invert); } public Exclusion(String pattern, ExclusionType exclusionType, boolean invert) { this.matcher = Pattern.compile(pattern).matcher(""); this.rawPattern = pattern; this.invert = invert; this.exclusionType = exclusionType; } public boolean matches(String other, ExclusionType type) { if (type == ExclusionType.GLOBAL || type == exclusionType) { return true; } return invert != matcher.reset(other).matches(); } @Override public boolean equals(Object o) { if (o instanceof Exclusion) { return Objects.equals(rawPattern, ((Exclusion) o).rawPattern); } return false; } @Override public int hashCode() { return Objects.hash(rawPattern); } public enum ExclusionType { GLOBAL, OPTIMIZER, SHRINKER, ADD_BRIDGE_ACCESS_FLAG, ADD_DEPRECATED_ACCESS_FLAG, ADD_SYNTHETIC_ACCESS_FLAG, ADD_TRASH_CLASSES, RENAMER, RESOURCE_RENAMER, SCRAMBLE_LINE_NUMBERS, STRING_OBFUSCATION, REFERENCE_OBFUSCATION, NUMBER_OBFUSCATION, FLOW_OBFUSCATION, ANTI_TAMPER, INJECT_ANTI_DEBUGGER, INJECT_EXPIRATION_KILL_SWITCH, ANTI_MEMORY_DUMP, VIRTUALIZER, PACKER, WATERMARK, SHUFFLE_MEMBERS; // fixme public static ExclusionType forIdentifier(String identifier) { // This is O(n), but should be fine since this is run only during config load for (var type : values()) { if (type.name().equalsIgnoreCase(identifier)) { return type; } } return GLOBAL; } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/exclusions/ExclusionManager.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.exclusions; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class ExclusionManager { private final Set exclusions; private final Map cache; public ExclusionManager(Map patterns) { this.exclusions = new HashSet<>(patterns.size()); this.cache = new HashMap<>(); patterns.forEach((k, v) -> { var invert = false; if (k.startsWith("!")) { invert = true; k = k.substring(1); } exclusions.add(new Exclusion(v, Exclusion.ExclusionType.forIdentifier(k), invert)); }); } public boolean find(String other, Exclusion.ExclusionType exclusionType) { // fixme: flawed cache logic if (cache.containsKey(other)) { return cache.get(other); } var result = exclusions.stream().anyMatch(exclusion -> exclusion.matches(other, exclusionType)); cache.put(other, result); return result; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/Transformer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import xyz.itzsomebody.radon.Radon; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.config.ObfConfig; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.asm.FieldWrapper; import xyz.itzsomebody.radon.utils.asm.MethodWrapper; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.stream.Stream; public abstract class Transformer implements Opcodes { private Radon radon; public void init(Radon radon) { this.radon = radon; } protected Collection classes() { return radon.getClasses().values(); } protected Stream classStream() { return classes().stream(); } protected Map classMap() { return radon.getClasses(); } protected Map classPathMap() { return radon.getClasspath(); } protected Map resourceMap() { return radon.getResources(); } protected boolean notExcluded(ClassWrapper wrapper) { return notExcluded(wrapper.getOriginalName()); } protected boolean notExcluded(MethodWrapper wrapper) { return notExcluded(wrapper.getOwner().getOriginalName() + ' ' + wrapper.getOriginalName() + wrapper.getOriginalDescriptor()); } protected boolean notExcluded(FieldWrapper wrapper) { return notExcluded(wrapper.getOwner().getOriginalName() + ' ' + wrapper.getOriginalName() + ' ' + wrapper.getOriginalType()); } protected boolean notExcluded(String checkThis) { return !radon.getExclusionManager().find(checkThis, getExclusionType()); } protected void addClass(ClassWrapper classWrapper) { radon.getClasses().put(classWrapper.getName(), classWrapper); radon.getClasspath().put(classWrapper.getName(), classWrapper); } protected void addClass(ClassNode classNode) { addClass(new ClassWrapper(classNode, false)); addClass(new ClassWrapper(classNode, false)); } protected ClassWrapper randomClass() { var list = new ArrayList<>(classMap().values()); return list.get(RandomUtils.randomInt(list.size())); } protected String fakeSubClass() { var list = new ArrayList<>(classMap().keySet()); var base = list.get(RandomUtils.randomInt(list.size())); var sub = list.get(RandomUtils.randomInt(list.size())); return base + '$' + sub.substring(sub.lastIndexOf('/') + 1); } public String getName() { return getClass().getName(); } public abstract void transform(); public abstract Exclusion.ExclusionType getExclusionType(); public abstract String getConfigName(); } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/Transformers.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers; import xyz.itzsomebody.radon.transformers.misc.*; import xyz.itzsomebody.radon.transformers.strings.AESPCBCStringEncryption; import xyz.itzsomebody.radon.transformers.strings.StaticFieldStrPool; import xyz.itzsomebody.radon.transformers.strings.Str2Base64Encoding; public enum Transformers { // Misc. ADD_BRIDGE_ACCESS_FLAG(AddBridgeAccess.class), ADD_DEPRECATED_ACCESS_FLAG(AddDeprecatedAccess.class), ADD_SYNTHETIC_ACCESS_FLAG(AddSyntheticAccess.class), ADD_TRASH_CLASSES(AddTrashClasses.class), INJECT_ANTI_DEBUGGER(AntiDebugger.class), INJECT_EXPIRATION_KILL_SWITCH(ExpirationKillSwitch.class), RENAMER(Renamer.class), RESOURCE_RENAMER(ResourceRenamer.class), SCRAMBLE_LINE_NUMBERS(ScrambleLineNumbers.class), SHUFFLE_MEMBERS(ShuffleMembers.class), WATERMARK(Watermarker.class), // String encryption/encoding STRING_TO_BASE64_ENCODING(Str2Base64Encoding.class), POOL_STRINGS_TO_STATIC_FIELD(StaticFieldStrPool.class), AES_PCBC_STRING_ENCRYPTION(AESPCBCStringEncryption.class), ;//TODO private final Class transformerClass; Transformers(Class transformerClass) { this.transformerClass = transformerClass; } public Class getTransformerClass() { return transformerClass; } public String getConfigName() { return name().toLowerCase(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/exploiter/ExploiterTransformer.java ================================================ package xyz.itzsomebody.radon.transformers.exploiter; public class ExploiterTransformer { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/flow/FlowTransformer.java ================================================ package xyz.itzsomebody.radon.transformers.flow; public class FlowTransformer { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/math/NumberTransformer.java ================================================ package xyz.itzsomebody.radon.transformers.math; public class NumberTransformer { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/AddBridgeAccess.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import org.objectweb.asm.Opcodes; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.concurrent.atomic.AtomicInteger; public class AddBridgeAccess extends Transformer { @Override public void transform() { var count = new AtomicInteger(); classes().stream().filter(this::notExcluded).forEach(cw -> { cw.methodStream().filter(mw -> notExcluded(mw) && !mw.hasVisibleAnnotations()).forEach(mw -> { // Adding ACC_BRIDGE to init / clinit is e-legal if (!mw.getMethodNode().name.startsWith("<") && !mw.isBridge()) { mw.addAccessFlags(Opcodes.ACC_BRIDGE); count.incrementAndGet(); } }); }); RadonLogger.info("Added bridge access flags to " + count.get() + " methods"); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.ADD_BRIDGE_ACCESS_FLAG; } @Override public String getConfigName() { return Transformers.ADD_BRIDGE_ACCESS_FLAG.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/AddDeprecatedAccess.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.Opcodes; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.concurrent.atomic.AtomicInteger; public class AddDeprecatedAccess extends Transformer { @JsonProperty("add_to_classes") private boolean doClasses; @JsonProperty("add_to_methods") private boolean doMethods; @JsonProperty("add_to_fields") private boolean doFields; @Override public void transform() { var classCount = new AtomicInteger(); var methodCount = new AtomicInteger(); var fieldCount = new AtomicInteger(); if (doClasses || doFields || doMethods) { classes().stream().filter(this::notExcluded).forEach(cw -> { if (doFields) { cw.fieldStream().filter(this::notExcluded).forEach(fw -> { if (!fw.isDeprecated()) { fw.addAccessFlags(Opcodes.ACC_DEPRECATED); fieldCount.incrementAndGet(); } }); } if (doMethods) { cw.methodStream().filter(this::notExcluded).forEach(mw -> { if (!mw.isDeprecated()) { mw.addAccessFlags(Opcodes.ACC_DEPRECATED); methodCount.incrementAndGet(); } }); } if (doClasses) { if (!cw.isDeprecated()) { cw.addAccessFlags(Opcodes.ACC_DEPRECATED); classCount.incrementAndGet(); } } }); } RadonLogger.info(String.format("Added deprecated access flags to %d classes, %d methods, and %d fields", classCount.get(), methodCount.get(), fieldCount.get())); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.ADD_DEPRECATED_ACCESS_FLAG; } @Override public String getConfigName() { return Transformers.ADD_DEPRECATED_ACCESS_FLAG.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/AddSyntheticAccess.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.Opcodes; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.concurrent.atomic.AtomicInteger; public class AddSyntheticAccess extends Transformer { @JsonProperty("add_to_classes") private boolean doClasses; @JsonProperty("add_to_methods") private boolean doMethods; @JsonProperty("add_to_fields") private boolean doFields; @Override public void transform() { var classCount = new AtomicInteger(); var methodCount = new AtomicInteger(); var fieldCount = new AtomicInteger(); if (doClasses || doFields || doMethods) { classes().stream().filter(this::notExcluded).forEach(cw -> { if (doFields) { cw.fieldStream().filter(fw -> notExcluded(fw) && fw.hasVisibleAnnotations()).forEach(fw -> { if (!fw.isSynthetic()) { fw.addAccessFlags(Opcodes.ACC_SYNTHETIC); fieldCount.incrementAndGet(); } }); } if (doMethods) { cw.methodStream().filter(mw -> notExcluded(mw) && !mw.hasVisibleAnnotations()).forEach(mw -> { if (!mw.isSynthetic()) { mw.addAccessFlags(Opcodes.ACC_SYNTHETIC); methodCount.incrementAndGet(); } }); } if (doClasses) { if (!cw.hasVisibleAnnotations() && !cw.isSynthetic()) { cw.addAccessFlags(Opcodes.ACC_SYNTHETIC); classCount.incrementAndGet(); } } }); } RadonLogger.info(String.format("Added synthetic access flags to %d classes, %d methods, and %d fields", classCount.get(), methodCount.get(), fieldCount.get())); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.ADD_SYNTHETIC_ACCESS_FLAG; } @Override public String getConfigName() { return Transformers.ADD_SYNTHETIC_ACCESS_FLAG.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/AddTrashClasses.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Handle; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.dictionaries.DictionaryFactory; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.asm.ASMUtils; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.ArrayList; /** * Not really a transformer. This "transformer" generates unused classes full * of random bytecode. This is copy-pasted from radon 2 -- no need to rewrite. * * @author ItzSomebody */ public class AddTrashClasses extends Transformer { private static ArrayList DESCRIPTORS = new ArrayList<>(); @JsonProperty("dictionary") private Dictionary dictionary = DictionaryFactory.defaultDictionary(); @JsonProperty("number_of_trash_classes") private int nTrashClasses; static { DESCRIPTORS.add("Z"); DESCRIPTORS.add("C"); DESCRIPTORS.add("B"); DESCRIPTORS.add("S"); DESCRIPTORS.add("I"); DESCRIPTORS.add("F"); DESCRIPTORS.add("J"); DESCRIPTORS.add("D"); DESCRIPTORS.add("V"); } @Override public void transform() { ArrayList classNames = new ArrayList<>(classPathMap().keySet()); for (int i = 0; i < classNames.size() % 20; i++) { DESCRIPTORS.add("L" + classNames.get(RandomUtils.randomInt(classNames.size())) + ";"); } for (int i = 0; i < nTrashClasses; i++) { var classNode = generateClass(); var cw = new ClassWriter(0); cw.newUTF8("RADON" + RadonConstants.VERSION); classNode.accept(cw); resourceMap().put(classNode.name + ".class", cw.toByteArray()); } RadonLogger.info(String.format("Generated %d trash classes.", nTrashClasses)); } private ClassNode generateClass() { ClassNode classNode = createClass(fakeSubClass()); int methodsToGenerate = RandomUtils.randomInt(3) + 2; for (int i = 0; i < methodsToGenerate; i++) classNode.methods.add(methodGen()); return classNode; } private ClassNode createClass(String className) { ClassNode classNode = new ClassNode(); classNode.visit(49, ACC_SUPER + ACC_PUBLIC, className, null, "java/lang/Object", null); var mv = classNode.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); classNode.visitEnd(); return classNode; } private MethodNode methodGen() { String randDesc = descGen(); MethodNode method = new MethodNode(ACC_STATIC + ACC_PRIVATE, dictionary.next(), randDesc, null, null); int instructions = RandomUtils.randomInt(30) + 30; InsnList insns = new InsnList(); for (int i = 0; i < instructions; ++i) { insns.add(junkInstructions()); } Type returnType = Type.getReturnType(randDesc); switch (returnType.getSort()) { case Type.VOID: insns.add(new InsnNode(RETURN)); break; case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: if (RandomUtils.randomInt(10) % 2 == 1) insns.add(new InsnNode(ICONST_0)); else insns.add(new InsnNode(ICONST_1)); insns.add(new InsnNode(IRETURN)); break; case Type.FLOAT: insns.add(ASMUtils.getNumberInsn(RandomUtils.randomFloat())); insns.add(new InsnNode(FRETURN)); break; case Type.LONG: insns.add(ASMUtils.getNumberInsn(RandomUtils.randomLong())); insns.add(new InsnNode(LRETURN)); break; case Type.DOUBLE: insns.add(ASMUtils.getNumberInsn(RandomUtils.randomDouble())); insns.add(new InsnNode(DRETURN)); break; default: insns.add(new VarInsnNode(ALOAD, RandomUtils.randomInt(30))); insns.add(new InsnNode(ARETURN)); break; } method.instructions = insns; return method; } private String descGen() { StringBuilder sb = new StringBuilder("("); for (int i = 0; i < RandomUtils.randomInt(7); i++) sb.append(DESCRIPTORS.get(RandomUtils.randomInt(DESCRIPTORS.size()))); sb.append(")"); sb.append(DESCRIPTORS.get(RandomUtils.randomInt(DESCRIPTORS.size()))); return sb.toString(); } private AbstractInsnNode junkInstructions() { int index = RandomUtils.randomInt(20); switch (index) { case 0: return new MethodInsnNode(INVOKESTATIC, dictionary.next(), dictionary.next(), "(Ljava/lang/String;)V", false); case 1: return new FieldInsnNode(GETFIELD, dictionary.next(), dictionary.next(), "I"); case 2: return new InsnNode(RandomUtils.randomInt(16)); case 3: return new VarInsnNode(ALOAD, RandomUtils.randomInt(30)); case 4: return new IntInsnNode(BIPUSH, RandomUtils.randomInt(255)); case 5: return new IntInsnNode(SIPUSH, RandomUtils.randomInt(25565)); case 6: case 7: case 8: return new InsnNode(RandomUtils.randomInt(5)); case 9: return new LdcInsnNode(dictionary.next()); case 10: return new IincInsnNode(RandomUtils.randomInt(16), RandomUtils.randomInt(16)); case 11: return new MethodInsnNode(INVOKESPECIAL, dictionary.next(), dictionary.next(), "()V", false); case 12: return new MethodInsnNode(INVOKEVIRTUAL, dictionary.next(), dictionary.next(), "(Ljava/lang/Object;)Ljava/lang/Object;", false); case 13: return new VarInsnNode(ILOAD, RandomUtils.randomInt(30)); case 14: return new InsnNode(ATHROW); case 15: return new MethodInsnNode(INVOKEINTERFACE, dictionary.next(), dictionary.next(), "(I)I", false); case 16: Handle handle = new Handle(6, dictionary.next(), dictionary.next(), dictionary.next(), false); return new InvokeDynamicInsnNode(dictionary.next(), dictionary.next(), handle, RandomUtils.randomInt(5), RandomUtils.randomInt(5), RandomUtils.randomInt(5), RandomUtils.randomInt(5), RandomUtils.randomInt(5)); case 17: return new IntInsnNode(ANEWARRAY, RandomUtils.randomInt(30)); case 18: return new VarInsnNode(ASTORE, RandomUtils.randomInt(30)); case 19: default: return new VarInsnNode(ISTORE, RandomUtils.randomInt(30)); } } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.ADD_TRASH_CLASSES; } @Override public String getConfigName() { return Transformers.ADD_TRASH_CLASSES.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/AntiDebugger.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.io.PrintStream; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; /** * Blocks debugging options on the commandline. * * @author vovanre * @author itzsomebody */ /* * Note from itzsomebody: this is *really, really* easy to remove and/or bypass; however, I don't really want to * vest much time in anti-debugging. So as a result, I turned this into a production test of the codegen. :PP */ public class AntiDebugger extends Transformer { private static final String[] DEBUG_OPTIONS = new String[]{"-agentlib:jdwp", "-Xdebug", "-Xrunjdwp:", "-javaagent:"}; @JsonProperty("message") private String message = "java.lang.NullPointerException"; // lul private AtomicInteger debugOptionIndex; @Override public void transform() { var counter = new AtomicInteger(); debugOptionIndex = new AtomicInteger(); classes().stream().filter(cw -> !cw.isInterface() && notExcluded(cw)).forEach(cw -> { var clinit = cw.getMethodNode("", "()V"); if (clinit == null) { clinit = new MethodNode(ACC_PRIVATE | ACC_STATIC, "", "()V", null, null); clinit.visitInsn(RETURN); cw.addMethod(clinit); } var checkCount = RandomUtils.randomInt(1, DEBUG_OPTIONS.length); for (int i = 0; i < checkCount; i++) { clinit.instructions.insert(generateCheck()); counter.incrementAndGet(); } }); RadonLogger.info("Injected " + counter.get() + " anti-debugger checks"); } private InsnList generateCheck() { var trueBlock = new BytecodeBlock(); if (RandomUtils.randomBoolean()) { trueBlock.append(getStatic( WrappedType.from(System.class), "out", WrappedType.from(PrintStream.class) ).invoke( "println", List.of(WrappedType.from(String.class)), WrappedType.from(void.class), stringConst(message) ).getInstructions()); if (RandomUtils.randomBoolean()) { trueBlock.append(invokeStatic( WrappedType.from(System.class), "exit", List.of(intConst(RandomUtils.randomInt())), List.of(WrappedType.from(int.class)), WrappedType.from(void.class) ).getInstructions()); } else { trueBlock.append(invokeStatic( WrappedType.from(Runtime.class), "getRuntime", Collections.emptyList(), Collections.emptyList(), WrappedType.from(Runtime.class) ).invoke( "halt", List.of(WrappedType.from(int.class)), WrappedType.from(void.class), intConst(RandomUtils.randomInt()) ).getInstructions()); } } else { trueBlock.append(newInstance( WrappedType.from(RuntimeException.class), List.of(WrappedType.from(String.class)), List.of(stringConst(message)) ).throwMe().getInstructions()); } return ifBlock( isDebugExpression().getInstructions(), trueBlock, new BytecodeBlock() ).getInstructions().compile(); } private IRExpression isDebugExpression() { var isUpper = RandomUtils.randomBoolean(); var argument = DEBUG_OPTIONS[debugOptionIndex.incrementAndGet() % DEBUG_OPTIONS.length]; argument = isUpper ? argument.toUpperCase() : argument.toLowerCase(); var getArguments = invokeVirtual( invokeVirtual( invokeVirtual( invokeStatic(WrappedType.from(ManagementFactory.class), "getRuntimeMXBean", Collections.emptyList(), Collections.emptyList(), WrappedType.from(RuntimeMXBean.class)), WrappedType.from(RuntimeMXBean.class), "getInputArguments", Collections.emptyList(), Collections.emptyList(), WrappedType.from(List.class) ), WrappedType.from(Object.class), "toString", Collections.emptyList(), Collections.emptyList(), WrappedType.from(String.class) ), WrappedType.from(String.class), isUpper ? "toUpperCase" : "toLowerCase", Collections.emptyList(), Collections.emptyList(), WrappedType.from(String.class) ); return invokeVirtual( getArguments, WrappedType.from(String.class), "contains", List.of(stringConst(argument)), List.of(WrappedType.from(CharSequence.class)), WrappedType.from(boolean.class) ); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.INJECT_ANTI_DEBUGGER; } @Override public String getConfigName() { return Transformers.INJECT_ANTI_DEBUGGER.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/ExpirationKillSwitch.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.tree.InsnList; import xyz.itzsomebody.codegen.BytecodeBlock; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import javax.swing.*; import java.awt.*; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; /** * Inserts an expiration block of instructions in each constructor method. * * @author itzsomebody */ /* * Another really easy thing to patch out. So I also turned this into a production test of codegen. */ public class ExpirationKillSwitch extends Transformer { private static final Class[] EXCEPTIONS = { Throwable.class, Exception.class, RuntimeException.class, NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class }; @JsonProperty("message") private String message = "tucks"; private long expirationTime; @JsonProperty("inject_joption_pane") private boolean injectJOptionPane; @JsonProperty("expiration_time") public void setExpirationTime(String date) { try { expirationTime = new SimpleDateFormat("MM/dd/yyyy").parse(date).getTime(); } catch (ParseException e) { throw new PreventableRadonException("Error parsing " + date + " into format MM/dd/yyyy: (" + e.getMessage() + ", offset=" + e.getErrorOffset() + ")"); } } @Override public void transform() { var counter = new AtomicInteger(); classes().stream().filter(this::notExcluded).forEach(cw -> { cw.methodStream().filter(mw -> notExcluded(mw) && mw.getMethodNode().name.startsWith("<")).forEach(mw -> { mw.getMethodNode().instructions.insert(generateExpirationCode()); counter.incrementAndGet(); }); }); RadonLogger.info("Added " + counter.get() + " expiration code blocks"); } // For reference private static void example() { // replace 0L with time and "tucks" with message if (new Date().after(new Date(0L))) { JOptionPane.showMessageDialog(null, "tucks"); throw new RuntimeException("tucks"); } } private InsnList generateExpirationCode() { var condition = new BytecodeBlock() .append( newInstance( WrappedType.from(Date.class), Collections.emptyList(), Collections.emptyList() ).invoke( "after", List.of(WrappedType.from(Date.class)), WrappedType.from(boolean.class), newInstance( WrappedType.from(Date.class), List.of(WrappedType.from(long.class)), List.of(longConst(expirationTime)) ) ).getInstructions() ); var trueBlock = new BytecodeBlock(); if (injectJOptionPane) { trueBlock.append(invokeStatic( WrappedType.from(JOptionPane.class), "showMessageDialog", List.of(nullConst(Component.class), stringConst(message)), List.of(WrappedType.from(Component.class), WrappedType.from(Object.class)), WrappedType.from(void.class) ).getInstructions()); } trueBlock.append(newInstance( WrappedType.from(EXCEPTIONS[RandomUtils.randomInt(EXCEPTIONS.length)]), List.of(WrappedType.from(String.class)), List.of(stringConst(message)) ).throwMe().getInstructions()); return ifBlock(condition, trueBlock, new BytecodeBlock()).getInstructions().compile(); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.INJECT_EXPIRATION_KILL_SWITCH; } @Override public String getConfigName() { return Transformers.INJECT_EXPIRATION_KILL_SWITCH.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/Packer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; public class Packer { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/Renamer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.tree.ClassNode; import xyz.itzsomebody.radon.Radon; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.dictionaries.DictionaryFactory; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.IOUtils; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.asm.FieldWrapper; import xyz.itzsomebody.radon.utils.asm.MethodWrapper; import xyz.itzsomebody.radon.utils.asm.RadonRemapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.IntStream; public class Renamer extends Transformer { @JsonProperty("resources_to_adapt") private List resourceToAdapt = Collections.emptyList(); @JsonProperty("dump_mappings") private boolean dumpMappings; @JsonProperty("repackaging_prefix") private String repackagingPrefix; @JsonProperty("class_name_dictionary") private Dictionary classNameDictionary = DictionaryFactory.defaultDictionary(); @JsonProperty("method_name_dictionary") private Dictionary methodNameDictionary = DictionaryFactory.defaultDictionary(); @JsonProperty("field_name_dictionary") private Dictionary fieldNameDictionary = DictionaryFactory.defaultDictionary(); private final Map mappings = new HashMap<>(); @Override public void transform() { RadonLogger.info("Building inheritance hierarchy graph"); long current = System.currentTimeMillis(); Radon.getInstance().buildHierarchyGraph(); RadonLogger.info(String.format("Finished building inheritance graph [%dms]", (System.currentTimeMillis() - current))); RadonLogger.info("Generating mappings"); current = System.currentTimeMillis(); generateMappings(); RadonLogger.info(String.format("Finished generating mappings [%dms]", (System.currentTimeMillis() - current))); RadonLogger.info("Applying mappings"); current = System.currentTimeMillis(); applyMappings(); RadonLogger.info(String.format("Finished applying mappings [%dms]", (System.currentTimeMillis() - current))); RadonLogger.info("Adapting resources"); current = System.currentTimeMillis(); adaptResources(); RadonLogger.info(String.format("Finished adapting resources [%dms]", (System.currentTimeMillis() - current))); if (dumpMappings) { RadonLogger.info("Dumping mappings"); dumpMappings(); } } private void generateMappings() { classes().forEach(classWrapper -> { classWrapper.methodStream().filter(methodWrapped -> !cannotRenameMethod(classWrapper, methodWrapped, new HashSet<>())).forEach(methodWrapper -> { String newName; do { newName = methodNameDictionary.next(); } while (mappings.containsKey(classWrapper.getOriginalName() + '.' + methodWrapper.getOriginalName() + methodWrapper.getOriginalDescriptor()) && mappings.get(classWrapper.getOriginalName() + '.' + methodWrapper.getOriginalName() + methodWrapper.getOriginalDescriptor()).equals(newName)); generateMethodMappings(classWrapper, methodWrapper, newName); for (var mapping : mappings.keySet()) { if (mapping.startsWith("java/util/List.size") && mappings.get(mapping).contains("Cx")) { System.out.println("Working on " + classWrapper.getName() + '.' + methodWrapper.getOriginalName() + methodWrapper.getOriginalDescriptor() + ": " + mapping + " -> " + mappings.get(mapping)); break; } } }); classWrapper.fieldStream().filter(fieldWrapper -> !cannotRenameField(classWrapper, fieldWrapper)).forEach(fieldWrapper -> { String newName; do { newName = fieldNameDictionary.next(); } while (mappings.containsKey(classWrapper.getOriginalName() + '.' + fieldWrapper.getOriginalName() + ' ' + fieldWrapper.getOriginalType()) && mappings.get(classWrapper.getOriginalName() + '.' + fieldWrapper.getOriginalName() + ' ' + fieldWrapper.getOriginalType()).equals(newName)); generateFieldMappings(classWrapper, fieldWrapper, newName); }); if (notExcluded(classWrapper)) { if (repackagingPrefix == null) { repackagingPrefix = classNameDictionary.copy().randomStr(RandomUtils.randomInt(0xF)); } var newName = repackagingPrefix; if (!newName.isEmpty()) { newName += '/'; } String temp; do { temp = newName + classNameDictionary.next(); } while (classPathMap().containsKey(temp)); // Important to check classpath instead of input classes newName = temp; mappings.put(classWrapper.getOriginalName(), newName); } }); } private boolean cannotRenameMethod(ClassWrapper classWrapper, MethodWrapper wrapper, Set visited) { // Already visited so don't check if (!visited.add(classWrapper)) { return false; } // If excluded, we don't want to rename. // If we already mapped the tree, we don't want to waste time doing it again. if (!notExcluded(classWrapper.getOriginalName() + '.' + wrapper.getOriginalName() + wrapper.getOriginalDescriptor()) || mappings.containsKey(classWrapper.getOriginalName() + '.' + wrapper.getOriginalName() + wrapper.getOriginalDescriptor())) { return true; } // Native and main/premain methods should not be renamed // Init and clinit methods should also not be renamed (otherwise the jvm will get mad) if (wrapper.isNative() || wrapper.getOriginalName().equals("main") || wrapper.getOriginalName().equals("premain") || wrapper.getOriginalName().startsWith("<")) { return true; } // Static methods are never inherited if (wrapper.isStatic()) { // Renaming these particular enum methods will cause problems return classWrapper.isEnum() && (wrapper.getOriginalName().equals("valueOf") || wrapper.getOriginalName().equals("values")); } else { if (classWrapper.getOriginalName().startsWith("java/util")) { System.out.println("Checking " + classWrapper.getOriginalName() + '.' + wrapper.getOriginalName() + wrapper.getOriginalDescriptor()); } // Methods which override or inherit from external libs cannot be renamed if (classWrapper != wrapper.getOwner() && classWrapper.isLibraryNode() && classWrapper.methodStream().anyMatch(other -> other.getOriginalName().equals(wrapper.getOriginalName()) && other.getOriginalDescriptor().equals(wrapper.getOriginalDescriptor()))) { return true; } // Children are checked for exclusions // Parents are checked for exclusions and if they are library nodes return classWrapper.getParents().stream().anyMatch(parent -> cannotRenameMethod(parent, wrapper, visited)) || classWrapper.getChildren().stream().anyMatch(child -> cannotRenameMethod(child, wrapper, visited)); } } private void generateMethodMappings(ClassWrapper owner, MethodWrapper wrapper, String newName) { String key = owner.getOriginalName() + '.' + wrapper.getOriginalName() + wrapper.getOriginalDescriptor(); // This (supposedly) will prevent an infinite recursion because the tree was already renamed if (mappings.containsKey(key)) { return; } mappings.put(key, newName); if (!wrapper.isStatic()) { // Static methods cannot be overriden owner.getParents().forEach(parent -> generateMethodMappings(parent, wrapper, newName)); owner.getChildren().forEach(child -> generateMethodMappings(child, wrapper, newName)); } } private boolean cannotRenameField(ClassWrapper classWrapper, FieldWrapper wrapper) { if (!notExcluded(wrapper) || mappings.containsKey(classWrapper.getOriginalName() + '.' + wrapper.getOriginalName() + ' ' + wrapper.getOriginalType())) { return true; } return classWrapper.isEnum(); // Todo: enums are a pain to handle } private void generateFieldMappings(ClassWrapper owner, FieldWrapper wrapper, String newName) { String key = owner.getOriginalName() + '.' + wrapper.getOriginalName() + ' ' + wrapper.getOriginalType(); // This (supposedly) will prevent an infinite recursion because the tree was already renamed if (mappings.containsKey(key)) { return; } mappings.put(key, newName); if (!wrapper.isStatic()) { // Static fields cannot be inherited owner.getParents().forEach(parent -> generateFieldMappings(parent, wrapper, newName)); owner.getChildren().forEach(child -> generateFieldMappings(child, wrapper, newName)); } } private void applyMappings() { var remapper = new RadonRemapper(mappings); new ArrayList<>(classes()).forEach(classWrapper -> { var classNode = classWrapper.getClassNode(); var copy = new ClassNode(); classNode.accept(new ClassRemapper(copy, remapper)); // In order to preserve the original names to prevent exclusions from breaking, // we update the MethodNode/FieldNode/ClassNode each wrapper wraps instead. IntStream.range(0, copy.methods.size()).forEach(i -> { classWrapper.getMethods().get(i).setMethodNode(copy.methods.get(i)); }); IntStream.range(0, copy.fields.size()).forEach(i -> { classWrapper.getFields().get(i).setFieldNode(copy.fields.get(i)); }); classWrapper.setClassNode(copy); // Fix input/classpath classnames classMap().remove(classWrapper.getOriginalName()); classPathMap().remove(classWrapper.getOriginalName()); classMap().put(copy.name, classWrapper); classPathMap().put(copy.name, classWrapper); }); } private void adaptResources() { resourceToAdapt.forEach(resourceName -> { var resourceBytes = resourceMap().get(resourceName); if (resourceBytes == null) { RadonLogger.warn("Attempted to adapt nonexistent resource: " + resourceName); } var stringVer = new String(resourceBytes, StandardCharsets.UTF_8); for (var original : mappings.keySet()) { if (stringVer.contains(original.replace("/", "."))) { if (resourceName.equals("META-INF/MANIFEST.MF") || resourceName.equals("plugin.yml") || resourceName.equals("bungee.yml")) { stringVer = stringVer.replaceAll("(?<=[: ])" + original.replace("/", "."), mappings.get(original)).replace("/", "."); } else { stringVer = stringVer.replace(original.replace("/", "."), mappings.get(original)).replace("/", "."); } } } resourceMap().put(resourceName, stringVer.getBytes(StandardCharsets.UTF_8)); }); } private void dumpMappings() { var file = new File("mappings.txt"); if (file.exists()) { IOUtils.renameExistingFile(file); } try { file.createNewFile(); var bw = new BufferedWriter(new FileWriter(file)); mappings.forEach((oldName, newName) -> { try { bw.append(oldName).append(" -> ").append(newName).append("\n"); } catch (IOException ioe) { RadonLogger.warn(String.format("Caught IOException while attempting to write line \"%s -> %s\"", oldName, newName)); if (RadonConstants.VERBOSE) { ioe.printStackTrace(System.out); } } }); } catch (Throwable t) { RadonLogger.warn("Captured throwable upon attempting to generate mappings file: " + t.getMessage()); if (RadonConstants.VERBOSE) { t.printStackTrace(System.out); } } } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.RENAMER; } @Override public String getConfigName() { return Transformers.RENAMER.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/ResourceRenamer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.tree.ClassNode; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.dictionaries.DictionaryFactory; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.asm.ResourceNameRemapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class ResourceRenamer extends Transformer { private final Map mappings = new HashMap<>(); @JsonProperty private Dictionary dictionary = DictionaryFactory.defaultDictionary(); @Override public void transform() { RadonLogger.info("Generating mappings"); long current = System.currentTimeMillis(); generateMappings(); RadonLogger.info(String.format("Finished generating mappings [%dms]", (System.currentTimeMillis() - current))); RadonLogger.info("Applying mappings"); current = System.currentTimeMillis(); applyMappings(); RadonLogger.info(String.format("Finished applying mappings [%dms]", (System.currentTimeMillis() - current))); } private void generateMappings() { resourceMap().keySet().stream().filter(this::notExcluded).forEach(resourceName -> { String newName; do { newName = dictionary.next(); } while (resourceMap().containsKey(newName)); mappings.put(resourceName, newName); }); } private void applyMappings() { new ArrayList<>(classes()).forEach(classWrapper -> { var classNode = classWrapper.getClassNode(); var copy = new ClassNode(); classNode.accept(new ResourceNameRemapper(copy, mappings, classWrapper.getName())); classWrapper.setClassNode(copy); }); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.RESOURCE_RENAMER; } @Override public String getConfigName() { return Transformers.RESOURCE_RENAMER.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/ScrambleLineNumbers.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.tree.LineNumberNode; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.concurrent.atomic.AtomicInteger; public class ScrambleLineNumbers extends Transformer { @JsonProperty("random_origin") private int origin; @JsonProperty("random_bound") private int bound; @Override public void transform() { var count = new AtomicInteger(); classes().stream().filter(this::notExcluded).forEach(cw -> { cw.methodStream().filter(this::notExcluded).forEach(mw -> { mw.getMethodNode().instructions.forEach(insn -> { if (insn instanceof LineNumberNode) { ((LineNumberNode) insn).line = RandomUtils.randomInt(origin, bound); count.incrementAndGet(); } }); }); }); RadonLogger.info("Scrambled " + count.get() + " lines"); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.SCRAMBLE_LINE_NUMBERS; } @Override public String getConfigName() { return Transformers.SCRAMBLE_LINE_NUMBERS.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/ShuffleMembers.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; public class ShuffleMembers extends Transformer { @JsonProperty("shuffle_methods") private boolean shuffleMethods; @JsonProperty("shuffle_fields") private boolean shuffleFields; @Override public void transform() { if (shuffleFields || shuffleMethods) { var count = new AtomicInteger(); classes().stream().filter(this::notExcluded).forEach(cw -> { // FIXME: Also update list of method/field wrappers if (shuffleMethods) { Collections.shuffle(cw.getClassNode().methods); count.addAndGet(cw.getMethods().size()); } if (shuffleFields) { Collections.shuffle(cw.getClassNode().fields); count.addAndGet(cw.getFields().size()); } }); RadonLogger.info("Shuffled " + count.get() + " members"); } } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.SHUFFLE_MEMBERS; } @Override public String getConfigName() { return Transformers.SHUFFLE_MEMBERS.getConfigName(); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/misc/Watermarker.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.misc; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.VarInsnNode; import xyz.itzsomebody.commons.MaxLocalsUpdater; import xyz.itzsomebody.commons.matcher.InstructionPattern; import xyz.itzsomebody.commons.matcher.rules.IntConstRule; import xyz.itzsomebody.commons.matcher.rules.OpcodeRule; import xyz.itzsomebody.radon.exceptions.FatalRadonException; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.asm.ASMUtils; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.asm.MethodWrapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.*; import java.util.zip.ZipFile; public class Watermarker extends Transformer { @JsonProperty private String message = "tucks"; @JsonProperty private String key = "ginkoid"; @JsonProperty private int copies = 3; @Override public void transform() { ArrayList wrappersList = new ArrayList<>(classes()); for (int i = 0; i < copies; i++) { Deque cipheredCharacters = cipheredWatermark(); while (!cipheredCharacters.isEmpty()) { MethodWrapper wrapper = getInjectableMethod(wrappersList); MaxLocalsUpdater.update(wrapper.getMethodNode()); wrapper.getMethodNode().instructions.insert(createInstructions(cipheredCharacters, wrapper.getMethodNode().maxLocals)); wrapper.getMethodNode().maxLocals += 4; } } RadonLogger.info("Successfully injected watermark"); } private MethodWrapper getInjectableMethod(ArrayList wrappersList) { var missCount = 0; for (; missCount < 20; missCount++) { var wrapper = wrappersList.get(RandomUtils.randomInt(wrappersList.size())); if (!wrapper.getMethods().isEmpty()) { var method = wrapper.getMethods().get(RandomUtils.randomInt(wrapper.getMethods().size())); if (method.hasInstructions()) { return method; } } } throw new FatalRadonException("Could not find a suitable method to inject watermark into after " + missCount + " tries"); } private InsnList createInstructions(Deque ciphered, int offset) { var charXorKey = RandomUtils.randomInt(Character.MAX_VALUE); var xorChar = ciphered.pop() ^ charXorKey; var indexXorKey = RandomUtils.randomInt(Short.MIN_VALUE, Short.MAX_VALUE); var xorIndex = ciphered.size() ^ indexXorKey; InsnList instructions = new InsnList(); instructions.add(ASMUtils.getNumberInsn(charXorKey)); instructions.add(ASMUtils.getNumberInsn(xorChar)); instructions.add(ASMUtils.getNumberInsn(indexXorKey)); instructions.add(ASMUtils.getNumberInsn(xorIndex)); instructions.add(new VarInsnNode(ISTORE, offset + 1)); instructions.add(new VarInsnNode(ISTORE, offset + 2)); instructions.add(new VarInsnNode(ISTORE, offset + 3)); instructions.add(new VarInsnNode(ISTORE, offset + 4)); return instructions; } private Deque cipheredWatermark() { var ciphered = new ArrayDeque(); for (int i = 0; i < message.length(); i++) { ciphered.push((char) (message.charAt(i) ^ key.charAt(i % key.length()))); } return ciphered; } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.WATERMARK; } @Override public String getConfigName() { return Transformers.WATERMARK.getConfigName(); } public static class Extractor { private static final InstructionPattern PATTERN = new InstructionPattern( new IntConstRule(), new IntConstRule(), new IntConstRule(), new IntConstRule(), new OpcodeRule(ISTORE), new OpcodeRule(ISTORE), new OpcodeRule(ISTORE), new OpcodeRule(ISTORE) ); private final ZipFile file; private final String key; public Extractor(ZipFile file, String key) { this.file = file; this.key = key; } private boolean enoughInfo(Map charMap) { if (charMap.size() < 1) { return false; } for (var i = 0; i < charMap.size(); i++) { if (!charMap.containsKey(i)) { return false; } } return true; } private String constructString(Map embedMap) { var sb = new StringBuilder(); for (var i = 0; i < embedMap.size(); i++) { sb.append((char) embedMap.get(i)); } return sb.toString(); } private String decrypt(String enc, String key) { var messageChars = enc.toCharArray(); var keyChars = key.toCharArray(); var sb = new StringBuilder(); for (var i = 0; i < messageChars.length; i++) { sb.append((char) (messageChars[i] ^ keyChars[i % keyChars.length])); } return sb.toString(); } private void attemptExtract(ClassNode classNode, Map map) { classNode.methods.forEach(methodNode -> { if (methodNode.instructions.size() > 0) { var matcher = PATTERN.matcher(methodNode.instructions.getFirst()); if (matcher.find()) { matcher.getAllCaptured().forEach(captured -> { char character = (char) ( ASMUtils.getIntegerFromInsn(captured.get(0)) ^ ASMUtils.getIntegerFromInsn(captured.get(1)) ); int index = ( ASMUtils.getIntegerFromInsn(captured.get(2)) ^ ASMUtils.getIntegerFromInsn(captured.get(3)) ); map.put(index, character); }); } } }); } public String extractId() { Map map = new HashMap<>(); var entries = file.entries(); while (entries.hasMoreElements()) { var entry = entries.nextElement(); if (!entry.isDirectory() && entry.getName().endsWith(".class")) { try { var node = new ClassNode(); var reader = new ClassReader(file.getInputStream(entry)); reader.accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); attemptExtract(node, map); } catch (Throwable ignored) { } } } if (enoughInfo(map)) { return "Found watermark: " + decrypt(constructString(map), key); } return "Unable to extract watermarked id (does it exist?)"; } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/references/ReferenceTransformer.java ================================================ package xyz.itzsomebody.radon.transformers.references; public class ReferenceTransformer { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveDeprecatedAccess.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveDeprecatedAccess { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveInnerClassesAttribute.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveInnerClassesAttribute { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveInvisibleAnnotations.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveInvisibleAnnotations { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveInvisibleParameterAnnotations.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveInvisibleParameterAnnotations { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveInvisibleTypeAnnotations.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveInvisibleTypeAnnotations { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveLineNumbers.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveLineNumbers { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveLocalVariableTable.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveLocalVariableTable { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveOuterMethodAttribute.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveOuterMethodAttribute { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveSignatureAttribute.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveSignatureAttribute { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveSourceDebugAttribute.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveSourceDebugAttribute { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveSourceFileAttribute.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveSourceFileAttribute { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveSyntheticAccessAttribute.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveSyntheticAccessAttribute { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveUnknownAttributes.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveUnknownAttributes { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveVisibleAnnotations.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveVisibleAnnotations { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveVisibleParameterAnnotations.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveVisibleParameterAnnotations { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/RemoveVisibleTypeAnnotations.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class RemoveVisibleTypeAnnotations { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/shrinker/ShrinkerTransformer.java ================================================ package xyz.itzsomebody.radon.transformers.shrinker; public class ShrinkerTransformer { } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/strings/AESPCBCEncryptor.java ================================================ package xyz.itzsomebody.radon.transformers.strings; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; public class AESPCBCEncryptor { private static int[][] sbox; // lookup table for SBox private static int[][] mcTables; // lookup tables for MixColumns private static int[] rcon; // round constants private static int[] W; // expanded key static { initMultLookups(); initSBox(); initRcon(); } private static void initSBox() { sbox = new int[0x10][0x10]; int p = 1; int q = 1; // See https://crypto.stackexchange.com/questions/85670/need-help-understanding-math-behind-rijndael-s-box // for an explanation of how 3 generates GF[2^8] do { p = gfMult(0x3, p); q = gfMult(0xF6, q); int trans = q; // Affine transformation trans ^= ((q << 1) | (q >>> (8 - 1))) & 0xFF; trans ^= ((q << 2) | (q >>> (8 - 2))) & 0xFF; trans ^= ((q << 3) | (q >>> (8 - 3))) & 0xFF; trans ^= ((q << 4) | (q >>> (8 - 4))) & 0xFF; sbox[p / 16][p % 16] = (trans ^ 0x63) & 0xFF; } while (p != 1); sbox[0][0] = 0x63; // 0 is never invertible so set manually } // Multiply in GF[2^8] private static int gfMult(int mult, int b) { int result = 0; for (int i = 0; i < 8; i++) { if ((mult & 0x1) != 0) { result ^= b; } mult >>= 1; int mod = 0; if ((b & 0x80) != 0) { mod = 0x11B; } b = (b << 1) ^ mod; } return result; } private static void initMultLookups() { mcTables = new int[0xF][]; mcTables[0x1] = new int[0x100]; mcTables[0x2] = new int[0x100]; mcTables[0x3] = new int[0x100]; for (int mult = 0; mult < mcTables.length; mult++) { if (mcTables[mult] != null) { int[] table = mcTables[mult]; for (int n = 0; n < table.length; n++) { table[n] = gfMult(mult, n); } } } } private static void initRcon() { rcon = new int[10]; for (int i = 0; i < rcon.length; i++) { if (i == 0) { rcon[i] = 1; } else if (rcon[i - 1] < 0x80) { rcon[i] = 2 * rcon[i - 1]; } else if (rcon[i - 1] >= 0x80) { rcon[i] = (2 * rcon[i - 1]) ^ 0x11B; } else { throw new RuntimeException("?"); } } for (int i = 0; i < rcon.length; i++) { rcon[i] <<= 24; } } private static void cipher(int[][] state) { int round = 0; addRoundKey(state, round); for (round = 1; round < 10; round++) { subBytes(state); shiftRows(state); mixColumns(state); addRoundKey(state, round); } subBytes(state); shiftRows(state); addRoundKey(state, round); } private static int[] pad(int[] arr) { int bytesNeeded = 16 - arr.length % 16; int[] paddedArr = new int[arr.length + bytesNeeded]; System.arraycopy(arr, 0, paddedArr, 0, arr.length); for (int i = 0; i < bytesNeeded; i++) { paddedArr[arr.length + i] = bytesNeeded; } return paddedArr; } private static int[] design(byte[] arr) { int[] designed = new int[arr.length]; for (int i = 0; i < arr.length; i++) { designed[i] = arr[i] & 0xFF; } return designed; } private static byte[] sign(int[] arr) { byte[] signed = new byte[arr.length]; for (int i = 0; i < arr.length; i++) { signed[i] = (byte) arr[i]; } return signed; } public static String encrypt(String input, int[] key, long[] ivInts) { // Key stuff keySchedule(key); // Convert IV to correct format int[] ivBytes = new int[0x10]; for (int i = 0; i < ivInts.length; i++) { for (int j = 0; j < 8; j++) { ivBytes[i * 8 + j] = (int) ((ivInts[i] >>> (56 - j * 8)) & 0xFF); } } int[][] iv = create_state(ivBytes); // Pad and create state block int[] paddedArr = pad(design(input.getBytes(StandardCharsets.UTF_8))); int[][][] states = new int[paddedArr.length / 16][][]; for (int i = 0; i < states.length; i++) { int[] subarray = Arrays.copyOfRange(paddedArr, i * 16, (i + 1) * 16); states[i] = create_state(subarray); } // PCBC encryption algorithm int[][] blockCopy = copyBlock(states[0]); // plaintext here for (int row = 0; row < states[0].length; row++) { for (int col = 0; col < states[0][0].length; col++) { states[0][row][col] ^= iv[row][col]; } } cipher(states[0]); for (int row = 0; row < states[0].length; row++) { for (int col = 0; col < states[0][0].length; col++) { blockCopy[row][col] ^= states[0][row][col]; // states[0] is ciphered here } } for (int i = 1; i < states.length; i++) { int[][] blockCopy2 = copyBlock(states[i]); int[][] state = states[i]; for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[0].length; col++) { state[row][col] ^= blockCopy[row][col]; } } cipher(states[i]); for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[0].length; col++) { blockCopy2[row][col] ^= state[row][col]; // state is ciphered here } } blockCopy = blockCopy2; } // Convert state to single-dimension array byte[] processed = new byte[paddedArr.length]; for (int i = 0; i < states.length; i++) { int[] vector = new int[0x10]; for (int col = 0; col < states[0].length; col++) { for (int row = 0; row < states[0][0].length; row++) { vector[col * 4 + row] = states[i][row][col]; } } System.arraycopy(sign(vector), 0, processed, i * 16, vector.length); } // Encode with B64 (prevents String UTF8 encoding/decoding messing the bytes up) // You could also just encode the bytes into a char if you want weird unprintable characters return Base64.getEncoder().encodeToString(processed); } public static int[][] copyBlock(int[][] block) { int[][] copy = new int[block.length][block[0].length]; for (int row = 0; row < block.length; row++) { for (int col = 0; col < block[0].length; col++) { copy[row][col] = block[row][col]; } } return copy; } public static int[][] create_state(int[] bytes) { int[][] state = new int[4][4]; for (int i = 0; i < bytes.length; i++) { state[i % 4][i / 4] = bytes[i]; } return state; } public static void subBytes(int[][] state) { for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[row].length; col++) { int s = state[row][col]; int upper = s >> 4; int lower = s & 0xF; state[row][col] = sbox[upper][lower]; } } } public static void shiftRows(int[][] state) { for (int offset = 0; offset < state.length; offset++) { int[] row = state[offset]; int[] shifted = new int[row.length]; for (int i = 0; i < row.length; i++) { shifted[i] = row[(i + offset) % 4]; } state[offset] = shifted; } } public static void mixColumns(int[][] state) { for (int col = 0; col < state[0].length; col++) { int s1 = mcTables[0x2][state[0][col]] ^ mcTables[0x3][state[1][col]] ^ mcTables[0x1][state[2][col]] ^ mcTables[0x1][state[3][col]]; int s2 = mcTables[0x1][state[0][col]] ^ mcTables[0x2][state[1][col]] ^ mcTables[0x3][state[2][col]] ^ mcTables[0x1][state[3][col]]; int s3 = mcTables[0x1][state[0][col]] ^ mcTables[0x1][state[1][col]] ^ mcTables[0x2][state[2][col]] ^ mcTables[0x3][state[3][col]]; int s4 = mcTables[0x3][state[0][col]] ^ mcTables[0x1][state[1][col]] ^ mcTables[0x1][state[2][col]] ^ mcTables[0x2][state[3][col]]; state[0][col] = s1; state[1][col] = s2; state[2][col] = s3; state[3][col] = s4; } } public static int subWord(int word) { int b0 = (word >> (8 * 3)) & 0xFF; int b1 = (word >> (8 * 2)) & 0xFF; int b2 = (word >> 8) & 0xFF; int b3 = word & 0xFF; return (sbox[b0 >> 4][b0 & 0xF] << 8*3) | (sbox[b1 >> 4][b1 & 0xF] << 8*2) | (sbox[b2 >> 4][b2 & 0xF] << 8) | (sbox[b3 >> 4][b3 & 0xF]); } public static void keySchedule(int[] key) { // AES-128 has 11 round keys int R = 11; W = new int[4*R]; for (int i = 0; i < W.length; i++) { if (i < key.length) { W[i] = key[i]; } else if (i % key.length == 0) { int b = (W[i - 1] << 8) | (W[i - 1] >>> (32 - 8)); W[i] = W[i - key.length]; W[i] ^= subWord(b); W[i] ^= rcon[i / key.length - 1]; } else { W[i] = W[i - key.length] ^ W[i - 1]; } } } public static void addRoundKey(int[][] state, int round) { for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[0].length; col++) { int rkey = W[round*state[0].length + col]; int xbyte = (rkey >> (8*(state.length - 1) - 8*row)) & 0xFF; state[row][col] ^= xbyte; } } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/strings/AESPCBCStringEncryption.java ================================================ package xyz.itzsomebody.radon.transformers.strings; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LdcInsnNode; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.commons.InsnListModifier; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.RandomUtils; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.asm.MethodWrapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; import static xyz.itzsomebody.codegen.expressions.IRExpressions.longConst; /** * I made this transformer as a project for my cryptography class. * This is an implementation of AES in the PCBC mode with 128 bit keys from (mostly) scratch. *

* For AES read this *

*

* For PCBC read this *

* @author ItzSomebody */ public class AESPCBCStringEncryption extends StringTransformer { @Override public void transform() { var stringsEncrypted = new AtomicInteger(); var memberNames = new DecryptionMemberNames(); classStream().filter(this::notExcluded).forEach(cw -> { cw.methodStream().filter(mw -> notExcluded(mw) && mw.hasInstructions()).forEach(mw -> { if (mw.getLeewaySize() <= allowedLeeway) { return; } var methodNode = mw.getMethodNode(); var modifier = new InsnListModifier(); methodNode.instructions.forEach(ain -> { if (ain instanceof LdcInsnNode && ((LdcInsnNode) ain).cst instanceof String) { String str = (String) ((LdcInsnNode) ain).cst; modifier.replace(ain, generateInsnBlock(str, cw, mw, memberNames)); stringsEncrypted.incrementAndGet(); } }); modifier.apply(methodNode); }); }); if (stringsEncrypted.get() > 0) { addClass(generateDecryptionClass(memberNames)); RadonLogger.info("Encrypted " + stringsEncrypted.get() + " strings"); } } @Override public String getConfigName() { return Transformers.AES_PCBC_STRING_ENCRYPTION.getConfigName(); } private InsnList generateInsnBlock(String str, ClassWrapper cw, MethodWrapper mw, DecryptionMemberNames memberNames) { int[] key = { memberNames.decryptorClassName.replace('/','.').hashCode(), memberNames.decryptMethodName.hashCode(), cw.getName().replace('/','.').hashCode(), mw.getMethodNode().name.replace('/','.').hashCode(), }; long[] ivInts = { RandomUtils.randomLong(), RandomUtils.randomLong() }; return invokeStatic( WrappedType.fromInternalName(memberNames.decryptorClassName, false), // Owner memberNames.decryptMethodName, // Method name List.of( stringConst(AESPCBCEncryptor.encrypt(str, key, ivInts)), newArray(long.class, longConst(ivInts[0]), longConst(ivInts[1])) ), // Args List.of( WrappedType.from(String.class), WrappedType.from(long[].class) ), // Arg types WrappedType.from(String.class) // Return type ).getInstructions().compile(); } private class DecryptionMemberNames { // Class name private String decryptorClassName = fakeSubClass(); // Field names private String sboxFieldName = dictionary.next(); private String invSBoxFieldName = dictionary.next(); private String rconFieldName = dictionary.next(); private String expandedKeyFieldName = dictionary.next(); private String mcTablesFieldName = dictionary.next(); // Method names private String subWordMethodName = dictionary.next(); private String keyScheduleMethodName = dictionary.next(); private String addRoundKeyMethodName = dictionary.next(); private String invShiftRowsMethodName = dictionary.next(); private String invSubBytesMethodName = dictionary.next(); private String gfMultMethodName = dictionary.next(); private String invMixColumnsMethodName = dictionary.next(); private String invCipherMethodName = dictionary.next(); private String decryptMethodName = dictionary.next(); private String copyBlockMethodName = dictionary.next(); private String designMethodName = dictionary.next(); private String resignMethodName = dictionary.next(); private String createStateMethodName = dictionary.next(); } private ClassNode generateDecryptionClass(DecryptionMemberNames memberNames) { ClassNode classWriter = new ClassNode(); FieldVisitor fieldVisitor; MethodVisitor methodVisitor; classWriter.visit(Opcodes.V11, ACC_PUBLIC | ACC_SUPER, memberNames.decryptorClassName, null, "java/lang/Object", null); classWriter.visitInnerClass("java/util/Base64$Decoder", "java/util/Base64", "Decoder", ACC_PUBLIC | ACC_STATIC); { fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, memberNames.sboxFieldName, "[[I", null, null); fieldVisitor.visitEnd(); } { fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, memberNames.invSBoxFieldName, "[[I", null, null); fieldVisitor.visitEnd(); } { fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, memberNames.rconFieldName, "[I", null, null); fieldVisitor.visitEnd(); } { fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, memberNames.expandedKeyFieldName, "[I", null, null); fieldVisitor.visitEnd(); } { fieldVisitor = classWriter.visitField(ACC_PUBLIC | ACC_STATIC, memberNames.mcTablesFieldName, "[[I", null, null); fieldVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "", "()V", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(1, 1); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.subWordMethodName, "(I)I", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitIntInsn(BIPUSH, 24); methodVisitor.visitInsn(ISHR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ISTORE, 1); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(ISHR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitInsn(ISHR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ISTORE, 3); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHR); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(BIPUSH, 24); methodVisitor.visitInsn(ISHL); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHR); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(ISHL); methodVisitor.visitInsn(IOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHR); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitInsn(ISHL); methodVisitor.visitInsn(IOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHR); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IOR); methodVisitor.visitInsn(IRETURN); methodVisitor.visitMaxs(4, 5); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.keyScheduleMethodName, "([I)V", null, null); methodVisitor.visitCode(); methodVisitor.visitIntInsn(BIPUSH, 11); methodVisitor.visitVarInsn(ISTORE, 1); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IMUL); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitFieldInsn(PUTSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label2 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); Label label3 = new Label(); methodVisitor.visitJumpInsn(GOTO, label3); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(IREM); Label label4 = new Label(); methodVisitor.visitJumpInsn(IFNE, label4); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitInsn(ISHL); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(BIPUSH, 24); methodVisitor.visitInsn(IUSHR); methodVisitor.visitInsn(IOR); methodVisitor.visitVarInsn(ISTORE, 3); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.subWordMethodName, "(I)I", false); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(IDIV); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitJumpInsn(GOTO, label3); methodVisitor.visitLabel(label4); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitLabel(label3); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(6, 4); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.addRoundKeyMethodName, "([[II)V", null, null); methodVisitor.visitCode(); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 3); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label3 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label3); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.expandedKeyFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(IMUL); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(IADD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IMUL); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IMUL); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(ISHR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ISTORE, 5); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ILOAD, 5); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(3, 1); methodVisitor.visitJumpInsn(GOTO, label2); methodVisitor.visitLabel(label3); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(4, 6); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.invShiftRowsMethodName, "([[I)V", null, null); methodVisitor.visitCode(); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 1); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ASTORE, 2); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitVarInsn(ASTORE, 3); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 4); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitInsn(ARRAYLENGTH); Label label3 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label3); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IADD); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(IREM); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(4, 1); methodVisitor.visitJumpInsn(GOTO, label2); methodVisitor.visitLabel(label3); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitInsn(AASTORE); methodVisitor.visitIincInsn(1, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(4, 5); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.invSubBytesMethodName, "([[I)V", null, null); methodVisitor.visitCode(); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 1); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label3 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label3); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ISTORE, 3); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHR); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ISTORE, 5); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.invSBoxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 5); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label2); methodVisitor.visitLabel(label3); methodVisitor.visitIincInsn(1, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(4, 6); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.gfMultMethodName, "(II)I", null, null); methodVisitor.visitCode(); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 3); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitIntInsn(BIPUSH, 8); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(IAND); Label label2 = new Label(); methodVisitor.visitJumpInsn(IFEQ, label2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISHR); methodVisitor.visitVarInsn(ISTORE, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitIntInsn(SIPUSH, 128); methodVisitor.visitInsn(IAND); Label label3 = new Label(); methodVisitor.visitJumpInsn(IFEQ, label3); methodVisitor.visitIntInsn(SIPUSH, 283); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitLabel(label3); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISHL); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 1); methodVisitor.visitIincInsn(3, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IRETURN); methodVisitor.visitMaxs(2, 5); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.invMixColumnsMethodName, "([[I)V", null, null); methodVisitor.visitCode(); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 1); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 14); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 11); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 13); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 14); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 11); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 13); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 3); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 13); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 14); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 11); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 11); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 13); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 14); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 5); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ILOAD, 5); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(1, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(4, 6); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.invCipherMethodName, "([[I)V", null, null); methodVisitor.visitCode(); methodVisitor.visitIntInsn(BIPUSH, 10); methodVisitor.visitVarInsn(ISTORE, 1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.addRoundKeyMethodName, "([[II)V", false); methodVisitor.visitIntInsn(BIPUSH, 9); methodVisitor.visitVarInsn(ISTORE, 1); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 1); Label label1 = new Label(); methodVisitor.visitJumpInsn(IFLE, label1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invShiftRowsMethodName, "([[I)V", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invSubBytesMethodName, "([[I)V", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.addRoundKeyMethodName, "([[II)V", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invMixColumnsMethodName, "([[I)V", false); methodVisitor.visitIincInsn(1, -1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invSubBytesMethodName, "([[I)V", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invShiftRowsMethodName, "([[I)V", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.addRoundKeyMethodName, "([[II)V", false); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(2, 2); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.decryptMethodName, "(Ljava/lang/String;[J)Ljava/lang/String;", null, null); methodVisitor.visitCode(); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); methodVisitor.visitVarInsn(ASTORE, 2); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitInsn(DUP); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); methodVisitor.visitInsn(IASTORE); methodVisitor.visitInsn(DUP); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); methodVisitor.visitInsn(IASTORE); methodVisitor.visitInsn(DUP); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); methodVisitor.visitInsn(IASTORE); methodVisitor.visitInsn(DUP); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ASTORE, 3); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.keyScheduleMethodName, "([I)V", false); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitVarInsn(ASTORE, 4); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 5); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 5); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 6); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 6); methodVisitor.visitIntInsn(BIPUSH, 8); Label label3 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label3); methodVisitor.visitVarInsn(ALOAD, 4); methodVisitor.visitVarInsn(ILOAD, 5); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitInsn(IMUL); methodVisitor.visitVarInsn(ILOAD, 6); methodVisitor.visitInsn(IADD); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitVarInsn(ILOAD, 5); methodVisitor.visitInsn(LALOAD); methodVisitor.visitIntInsn(BIPUSH, 56); methodVisitor.visitVarInsn(ILOAD, 6); methodVisitor.visitIntInsn(BIPUSH, 8); methodVisitor.visitInsn(IMUL); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(LUSHR); methodVisitor.visitLdcInsn(255L); methodVisitor.visitInsn(LAND); methodVisitor.visitInsn(L2I); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(6, 1); methodVisitor.visitJumpInsn(GOTO, label2); methodVisitor.visitLabel(label3); methodVisitor.visitIincInsn(5, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ALOAD, 4); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.createStateMethodName, "([I)[[I", false); methodVisitor.visitVarInsn(ASTORE, 5); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", "(Ljava/lang/String;)[B", false); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.designMethodName, "([B)[I", false); methodVisitor.visitVarInsn(ASTORE, 6); methodVisitor.visitVarInsn(ALOAD, 6); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(IDIV); methodVisitor.visitTypeInsn(ANEWARRAY, "[[I"); methodVisitor.visitVarInsn(ASTORE, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 8); Label label4 = new Label(); methodVisitor.visitLabel(label4); methodVisitor.visitVarInsn(ILOAD, 8); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ARRAYLENGTH); Label label5 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label5); methodVisitor.visitVarInsn(ALOAD, 6); methodVisitor.visitVarInsn(ILOAD, 8); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(IMUL); methodVisitor.visitVarInsn(ILOAD, 8); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(IADD); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(IMUL); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "copyOfRange", "([III)[I", false); methodVisitor.visitVarInsn(ASTORE, 9); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitVarInsn(ILOAD, 8); methodVisitor.visitVarInsn(ALOAD, 9); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.createStateMethodName, "([I)[[I", false); methodVisitor.visitInsn(AASTORE); methodVisitor.visitIincInsn(8, 1); methodVisitor.visitJumpInsn(GOTO, label4); methodVisitor.visitLabel(label5); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.copyBlockMethodName, "([[I)[[I", false); methodVisitor.visitVarInsn(ASTORE, 8); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invCipherMethodName, "([[I)V", false); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 9); Label label6 = new Label(); methodVisitor.visitLabel(label6); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label7 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 10); Label label8 = new Label(); methodVisitor.visitLabel(label8); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label9 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label9); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ALOAD, 5); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ALOAD, 8); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(10, 1); methodVisitor.visitJumpInsn(GOTO, label8); methodVisitor.visitLabel(label9); methodVisitor.visitIincInsn(9, 1); methodVisitor.visitJumpInsn(GOTO, label6); methodVisitor.visitLabel(label7); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitVarInsn(ISTORE, 9); Label label10 = new Label(); methodVisitor.visitLabel(label10); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ARRAYLENGTH); Label label11 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label11); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.copyBlockMethodName, "([[I)[[I", false); methodVisitor.visitVarInsn(ASTORE, 10); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.invCipherMethodName, "([[I)V", false); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitVarInsn(ILOAD, 9); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ASTORE, 11); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 12); Label label12 = new Label(); methodVisitor.visitLabel(label12); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitInsn(ARRAYLENGTH); Label label13 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label13); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 13); Label label14 = new Label(); methodVisitor.visitLabel(label14); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label15 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label15); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ALOAD, 8); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ALOAD, 10); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(13, 1); methodVisitor.visitJumpInsn(GOTO, label14); methodVisitor.visitLabel(label15); methodVisitor.visitIincInsn(12, 1); methodVisitor.visitJumpInsn(GOTO, label12); methodVisitor.visitLabel(label13); methodVisitor.visitVarInsn(ALOAD, 10); methodVisitor.visitVarInsn(ASTORE, 8); methodVisitor.visitIincInsn(9, 1); methodVisitor.visitJumpInsn(GOTO, label10); methodVisitor.visitLabel(label11); methodVisitor.visitVarInsn(ALOAD, 6); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitIntInsn(NEWARRAY, T_BYTE); methodVisitor.visitVarInsn(ASTORE, 9); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 10); Label label16 = new Label(); methodVisitor.visitLabel(label16); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ARRAYLENGTH); Label label17 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label17); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitVarInsn(ASTORE, 11); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 12); Label label18 = new Label(); methodVisitor.visitLabel(label18); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label19 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label19); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 13); Label label20 = new Label(); methodVisitor.visitLabel(label20); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label21 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label21); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(IMUL); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitInsn(IADD); methodVisitor.visitVarInsn(ALOAD, 7); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 13); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 12); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(13, 1); methodVisitor.visitJumpInsn(GOTO, label20); methodVisitor.visitLabel(label21); methodVisitor.visitIincInsn(12, 1); methodVisitor.visitJumpInsn(GOTO, label18); methodVisitor.visitLabel(label19); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.resignMethodName, "([I)[B", false); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ALOAD, 9); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(IMUL); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false); methodVisitor.visitIincInsn(10, 1); methodVisitor.visitJumpInsn(GOTO, label16); methodVisitor.visitLabel(label17); methodVisitor.visitVarInsn(ALOAD, 9); methodVisitor.visitVarInsn(ALOAD, 9); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(BALOAD); methodVisitor.visitVarInsn(ISTORE, 10); methodVisitor.visitVarInsn(ALOAD, 9); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitVarInsn(ILOAD, 10); methodVisitor.visitInsn(ISUB); methodVisitor.visitIntInsn(NEWARRAY, T_BYTE); methodVisitor.visitVarInsn(ASTORE, 11); methodVisitor.visitVarInsn(ALOAD, 9); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", false); methodVisitor.visitTypeInsn(NEW, "java/lang/String"); methodVisitor.visitInsn(DUP); methodVisitor.visitVarInsn(ALOAD, 11); methodVisitor.visitFieldInsn(GETSTATIC, "java/nio/charset/StandardCharsets", "UTF_8", "Ljava/nio/charset/Charset;"); methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([BLjava/nio/charset/Charset;)V", false); methodVisitor.visitInsn(ARETURN); methodVisitor.visitMaxs(7, 14); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.copyBlockMethodName, "([[I)[[I", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitMultiANewArrayInsn("[[I", 2); methodVisitor.visitVarInsn(ASTORE, 1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 3); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label3 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label3); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(3, 1); methodVisitor.visitJumpInsn(GOTO, label2); methodVisitor.visitLabel(label3); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARETURN); methodVisitor.visitMaxs(4, 4); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.designMethodName, "([B)[I", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitVarInsn(ASTORE, 1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(BALOAD); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARETURN); methodVisitor.visitMaxs(4, 3); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.resignMethodName, "([I)[B", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitIntInsn(NEWARRAY, T_BYTE); methodVisitor.visitVarInsn(ASTORE, 1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(I2B); methodVisitor.visitInsn(BASTORE); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARETURN); methodVisitor.visitMaxs(4, 3); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, memberNames.createStateMethodName, "([I)[[I", null, null); methodVisitor.visitCode(); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitMultiANewArrayInsn("[[I", 2); methodVisitor.visitVarInsn(ASTORE, 1); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ARRAYLENGTH); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(IREM); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(IDIV); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label0); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARETURN); methodVisitor.visitMaxs(4, 3); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_STATIC, "", "()V", null, null); methodVisitor.visitCode(); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitMultiANewArrayInsn("[[I", 2); methodVisitor.visitFieldInsn(PUTSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitVarInsn(ISTORE, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitVarInsn(ISTORE, 1); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.gfMultMethodName, "(II)I", false); methodVisitor.visitVarInsn(ISTORE, 0); methodVisitor.visitIntInsn(SIPUSH, 246); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.gfMultMethodName, "(II)I", false); methodVisitor.visitVarInsn(ISTORE, 1); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISHL); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitIntInsn(BIPUSH, 7); methodVisitor.visitInsn(IUSHR); methodVisitor.visitInsn(IOR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(ISHL); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitIntInsn(BIPUSH, 6); methodVisitor.visitInsn(IUSHR); methodVisitor.visitInsn(IOR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_3); methodVisitor.visitInsn(ISHL); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_5); methodVisitor.visitInsn(IUSHR); methodVisitor.visitInsn(IOR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHL); methodVisitor.visitVarInsn(ILOAD, 1); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(IUSHR); methodVisitor.visitInsn(IOR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IXOR); methodVisitor.visitVarInsn(ISTORE, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(IDIV); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitIntInsn(BIPUSH, 16); methodVisitor.visitInsn(IREM); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitIntInsn(BIPUSH, 99); methodVisitor.visitInsn(IXOR); methodVisitor.visitIntInsn(SIPUSH, 255); methodVisitor.visitInsn(IAND); methodVisitor.visitInsn(IASTORE); methodVisitor.visitVarInsn(ILOAD, 0); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitJumpInsn(IF_ICMPNE, label0); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitIntInsn(BIPUSH, 99); methodVisitor.visitInsn(IASTORE); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitMultiANewArrayInsn("[[I", 2); methodVisitor.visitFieldInsn(PUTSTATIC, memberNames.decryptorClassName, memberNames.invSBoxFieldName, "[[I"); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label1 = new Label(); methodVisitor.visitLabel(label1); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitInsn(ARRAYLENGTH); Label label2 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label2); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 3); Label label3 = new Label(); methodVisitor.visitLabel(label3); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitInsn(AALOAD); methodVisitor.visitInsn(ARRAYLENGTH); Label label4 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label4); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.sboxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(IALOAD); methodVisitor.visitVarInsn(ISTORE, 4); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.invSBoxFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHR); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitInsn(IAND); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_4); methodVisitor.visitInsn(ISHL); methodVisitor.visitVarInsn(ILOAD, 3); methodVisitor.visitInsn(IOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(3, 1); methodVisitor.visitJumpInsn(GOTO, label3); methodVisitor.visitLabel(label4); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label1); methodVisitor.visitLabel(label2); methodVisitor.visitIntInsn(BIPUSH, 10); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitFieldInsn(PUTSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label5 = new Label(); methodVisitor.visitLabel(label5); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitInsn(ARRAYLENGTH); Label label6 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label6); methodVisitor.visitVarInsn(ILOAD, 2); Label label7 = new Label(); methodVisitor.visitJumpInsn(IFNE, label7); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(IASTORE); Label label8 = new Label(); methodVisitor.visitJumpInsn(GOTO, label8); methodVisitor.visitLabel(label7); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(SIPUSH, 128); Label label9 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label9); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IMUL); methodVisitor.visitInsn(IASTORE); methodVisitor.visitJumpInsn(GOTO, label8); methodVisitor.visitLabel(label9); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(SIPUSH, 128); methodVisitor.visitJumpInsn(IF_ICMPLT, label8); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitInsn(IALOAD); methodVisitor.visitInsn(IMUL); methodVisitor.visitIntInsn(SIPUSH, 283); methodVisitor.visitInsn(IXOR); methodVisitor.visitInsn(IASTORE); methodVisitor.visitLabel(label8); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label5); methodVisitor.visitLabel(label6); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label10 = new Label(); methodVisitor.visitLabel(label10); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitInsn(ARRAYLENGTH); Label label11 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label11); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.rconFieldName, "[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(DUP2); methodVisitor.visitInsn(IALOAD); methodVisitor.visitIntInsn(BIPUSH, 24); methodVisitor.visitInsn(ISHL); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label10); methodVisitor.visitLabel(label11); methodVisitor.visitIntInsn(BIPUSH, 15); methodVisitor.visitTypeInsn(ANEWARRAY, "[I"); methodVisitor.visitFieldInsn(PUTSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 14); methodVisitor.visitIntInsn(SIPUSH, 256); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitInsn(AASTORE); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 11); methodVisitor.visitIntInsn(SIPUSH, 256); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitInsn(AASTORE); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 13); methodVisitor.visitIntInsn(SIPUSH, 256); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitInsn(AASTORE); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitIntInsn(BIPUSH, 9); methodVisitor.visitIntInsn(SIPUSH, 256); methodVisitor.visitIntInsn(NEWARRAY, T_INT); methodVisitor.visitInsn(AASTORE); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 2); Label label12 = new Label(); methodVisitor.visitLabel(label12); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitInsn(ARRAYLENGTH); Label label13 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label13); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(AALOAD); Label label14 = new Label(); methodVisitor.visitJumpInsn(IFNULL, label14); methodVisitor.visitFieldInsn(GETSTATIC, memberNames.decryptorClassName, memberNames.mcTablesFieldName, "[[I"); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitInsn(AALOAD); methodVisitor.visitVarInsn(ASTORE, 3); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitVarInsn(ISTORE, 4); Label label15 = new Label(); methodVisitor.visitLabel(label15); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitInsn(ARRAYLENGTH); methodVisitor.visitJumpInsn(IF_ICMPGE, label14); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitVarInsn(ILOAD, 2); methodVisitor.visitVarInsn(ILOAD, 4); methodVisitor.visitMethodInsn(INVOKESTATIC, memberNames.decryptorClassName, memberNames.gfMultMethodName, "(II)I", false); methodVisitor.visitInsn(IASTORE); methodVisitor.visitIincInsn(4, 1); methodVisitor.visitJumpInsn(GOTO, label15); methodVisitor.visitLabel(label14); methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(GOTO, label12); methodVisitor.visitLabel(label13); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(6, 5); methodVisitor.visitEnd(); } classWriter.visitEnd(); return classWriter; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/strings/StaticFieldStrPool.java ================================================ package xyz.itzsomebody.radon.transformers.strings; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.codegen.WrappedType; import xyz.itzsomebody.codegen.expressions.IRExpression; import xyz.itzsomebody.codegen.expressions.IRExpressions; import xyz.itzsomebody.commons.InsnListModifier; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import static xyz.itzsomebody.codegen.expressions.IRExpressions.*; /** * Takes all the strings in a class and stuffs them into a method which initializes a static field when * is invoked. * * @author itzsomebody */ public class StaticFieldStrPool extends StringTransformer { @Override public void transform() { var count = new AtomicInteger(); classStream().filter(this::notExcluded).forEach(classWrapper -> { var strList = new ArrayList(); var stringPoolInitMethodName = classWrapper.generateNextAllowedMethodName(dictionary.copy(), "()V"); var stringPoolFieldName = classWrapper.generateNextAllowedFieldName(dictionary.copy(), "[Ljava/lang/String;"); classWrapper.methodStream().filter(mw -> notExcluded(mw) && mw.hasInstructions()).forEach(methodWrapper -> { if (methodWrapper.getLeewaySize() > allowedLeeway) { var methodNode = methodWrapper.getMethodNode(); var modifier = new InsnListModifier(); methodNode.instructions.forEach(insn -> { if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof String) { var str = (String) ((LdcInsnNode) insn).cst; if (!isExcludedString(str)) { modifier.replace(insn, getArrayElement( getStatic(WrappedType.fromInternalName(classWrapper.getName(), classWrapper.isInterface()), stringPoolFieldName, WrappedType.from(String[].class)), intConst(strList.size()) ).getInstructions().compile()); strList.add(str); count.incrementAndGet(); } } }); modifier.apply(methodNode.instructions); } }); if (strList.size() != 0) { classWrapper.addMethod(createStringPoolInitializer(classWrapper, stringPoolInitMethodName, stringPoolFieldName, strList)); var clinit = classWrapper.getMethodNode("", "()V"); if (clinit == null) { clinit = new MethodNode(ACC_PRIVATE | ACC_STATIC, "", "()V", null, null); clinit.visitMethodInsn(INVOKESTATIC, classWrapper.getName(), stringPoolInitMethodName, "()V", false); clinit.visitInsn(RETURN); classWrapper.addMethod(clinit); } else { clinit.instructions.insert(new MethodInsnNode(INVOKESTATIC, classWrapper.getName(), stringPoolInitMethodName, "()V", false)); } classWrapper.addField(new FieldNode(ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, stringPoolFieldName, "[Ljava/lang/String;", null, null)); } }); RadonLogger.info("Pooled " + count.get() + " strings"); } @Override public String getConfigName() { return Transformers.POOL_STRINGS_TO_STATIC_FIELD.getConfigName(); } private static MethodNode createStringPoolInitializer(ClassWrapper owner, String name, String stringPool, ArrayList strings) { var method = new MethodNode(ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC | ACC_BRIDGE, name, "()V", null, null); var createArrayExpr = newArray(String.class, strings.stream().map(IRExpressions::stringConst).toArray(IRExpression[]::new)); var putStaticExpr = setStatic(WrappedType.fromInternalName(owner.getName(), owner.isInterface()), stringPool, WrappedType.from(String[].class), createArrayExpr); method.instructions = putStaticExpr.getInstructions().voidReturn().compile(); return method; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/strings/Str2Base64Encoding.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.strings; import com.fasterxml.jackson.annotation.JsonProperty; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.commons.InsnListModifier; import xyz.itzsomebody.radon.config.ConfigurationParser; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.concurrent.atomic.AtomicInteger; /** * Transformer which encodes Utf8 constants with Base64. This is here just so I can quickly test stuff. * Please don't use this and not expect your strings to get decoded, lol. * * @author itzsomebody */ public class Str2Base64Encoding extends StringTransformer { @JsonProperty("decode_from_random_class") private boolean decodeFromRandomClass; @Override public void transform() { ClassWrapper toInject; if (decodeFromRandomClass) { toInject = randomClass(); } else { ClassNode cn = new ClassNode(); cn.version = V1_5; cn.access = ACC_PUBLIC; cn.name = fakeSubClass(); cn.superName = "java/lang/Object"; toInject = new ClassWrapper(cn, false); addClass(toInject); } var decryptor = decryptorNode(toInject.generateNextAllowedMethodName(dictionary.copy(), "(Ljava/lang/String;)Ljava/lang/String;")); toInject.addMethod(decryptor); AtomicInteger count = new AtomicInteger(); classStream().filter(this::notExcluded).forEach(classWrapper -> { classWrapper.methodStream().filter(mw -> notExcluded(mw) && mw.hasInstructions()).forEach(methodWrapper -> { if (methodWrapper.getLeewaySize() > allowedLeeway) { var methodNode = methodWrapper.getMethodNode(); var modifier = new InsnListModifier(); methodNode.instructions.forEach(current -> { if (current instanceof LdcInsnNode && ((LdcInsnNode) current).cst instanceof String) { ((LdcInsnNode) current).cst = encodeString((String) ((LdcInsnNode) current).cst); modifier.insert(current, new MethodInsnNode( INVOKESTATIC, toInject.getName(), decryptor.name, decryptor.desc, toInject.isInterface() )); count.incrementAndGet(); } }); modifier.apply(methodNode.instructions); } }); }); RadonLogger.info("Base64 encoded " + count.get() + " strings"); } @Override public String getConfigName() { return Transformers.STRING_TO_BASE64_ENCODING.getConfigName(); } public static String encodeString(String s) { // It's important to treat everything as UTF-8 return new String(Base64.getEncoder().encode(s.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); } /** * Template for ASMifier. */ public static String decodeString(String s) { return new String(Base64.getDecoder().decode(s.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); } private MethodNode decryptorNode(String methodName) { var mw = new MethodNode(ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC | ACC_BRIDGE, methodName, "(Ljava/lang/String;)Ljava/lang/String;", null, null); mw.visitCode(); mw.visitTypeInsn(NEW, "java/lang/String"); mw.visitInsn(DUP); mw.visitMethodInsn(INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false); mw.visitVarInsn(ALOAD, 0); mw.visitFieldInsn(GETSTATIC, "java/nio/charset/StandardCharsets", "UTF_8", "Ljava/nio/charset/Charset;"); mw.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/nio/charset/Charset;)[B", false); mw.visitMethodInsn(INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", "([B)[B", false); mw.visitFieldInsn(GETSTATIC, "java/nio/charset/StandardCharsets", "UTF_8", "Ljava/nio/charset/Charset;"); mw.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([BLjava/nio/charset/Charset;)V", false); mw.visitInsn(ARETURN); mw.visitMaxs(5, 2); mw.visitEnd(); return mw; } enum Base64EncoderKey { DECODE_FROM_RANDOM_CLASS; public String getKey() { return name().toLowerCase(); } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/transformers/strings/StringTransformer.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.transformers.strings; import com.fasterxml.jackson.annotation.JsonProperty; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.dictionaries.DictionaryFactory; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformer; import java.util.Set; public abstract class StringTransformer extends Transformer { @JsonProperty("excluded_strings") private Set excludedStrings; @JsonProperty("dictionary") protected Dictionary dictionary = DictionaryFactory.defaultDictionary(); @JsonProperty("leeway") protected int allowedLeeway = 5000; protected boolean isExcludedString(String s) { return excludedStrings.contains(s); } @Override public Exclusion.ExclusionType getExclusionType() { return Exclusion.ExclusionType.STRING_OBFUSCATION; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/IOUtils.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; /** * Utility class for various I/O and File operations. * * @author itzsomebody */ public class IOUtils { /** * Return a given {@link InputStream} as a byte array. * * @return Byte array representation of provided {@link InputStream}. */ public static byte[] toByteArray(final InputStream stream) throws IOException { try (stream; var out = new ByteArrayOutputStream()) { var buf = new byte[0x1000]; int bytesRead; while ((bytesRead = stream.read(buf, 0, buf.length)) != -1) { out.write(buf, 0, bytesRead); } out.flush(); return out.toByteArray(); } } /** * Renames a {@link File} and returns the new name. * * @return The new {@link File} name. */ public static String renameExistingFile(File existing) { try { var i = 0; while (true) { i++; var newName = existing.getAbsolutePath() + ".BACKUP-" + i; var backUpName = new File(newName); if (!backUpName.exists()) { existing.renameTo(backUpName); return newName; } } } catch (Exception e) { e.printStackTrace(System.out); throw new PreventableRadonException(String.format("Could not backup \"%s\"", existing.getAbsolutePath())); } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/JarLoader.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils; import org.objectweb.asm.ClassReader; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.exceptions.FatalRadonException; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import xyz.itzsomebody.radon.utils.asm.ClassWrapper; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; public class JarLoader { private final Map classes = new HashMap<>(); private final Map classpath = new HashMap<>(); private final Map resources = new HashMap<>(); public void loadAsLib(String path) { RadonLogger.info("Loading library \"" + path + "\""); var file = new File(path); if (!file.exists()) { RadonLogger.warn("Library \"" + file.getAbsolutePath() + "\" doesn't exist. Skipping"); } if (!file.canRead()) { RadonLogger.warn("Library \"" + file.getAbsolutePath() + "\" doesn't have read permissions. Skipping"); } if (!file.isFile()) { RadonLogger.warn("Library \"" + file.getAbsolutePath() + "\" isn't a file. Skipping"); } try { var zipFile = new ZipFile(file); var entries = zipFile.entries(); ZipEntry currentEntry; while (entries.hasMoreElements()) { currentEntry = entries.nextElement(); if (!currentEntry.isDirectory() && currentEntry.getName().endsWith(".class")) { try (var stream = zipFile.getInputStream(currentEntry)) { var wrapper = ClassWrapper.fromLib(new ClassReader(stream)); classpath.put(wrapper.getName(), wrapper); } catch (Throwable t) { RadonLogger.warn(String.format("Error while loading library class: \"%s\"", currentEntry.getName())); if (RadonConstants.VERBOSE) { t.printStackTrace(); } } } } } catch (ZipException e) { RadonLogger.warn("Library \"" + file.getAbsolutePath() + "\" couldn't be loaded as a ZIP. Skipping"); if (RadonConstants.VERBOSE) { e.printStackTrace(); } } catch (IOException e) { RadonLogger.warn("Library \"" + file.getAbsolutePath() + "\" couldn't be loaded due to an IO error" + e.getMessage()); if (RadonConstants.VERBOSE) { e.printStackTrace(); } } } public void loadAsInput(String path) { RadonLogger.info("Loading input \"" + path + "\""); var file = new File(path); if (!file.exists()) { throw new PreventableRadonException("Input \"" + file.getAbsolutePath() + "\" doesn't exist"); } if (!file.canRead()) { throw new PreventableRadonException("Input \"" + file.getAbsolutePath() + "\" doesn't have read permissions"); } if (!file.isFile()) { throw new PreventableRadonException("Input \"" + file.getAbsolutePath() + "\" isn't a file"); } try { var zipFile = new ZipFile(file); var entries = zipFile.entries(); ZipEntry currentEntry; while (entries.hasMoreElements()) { currentEntry = entries.nextElement(); if (!currentEntry.isDirectory()) { try (var stream = zipFile.getInputStream(currentEntry)) { if (currentEntry.getName().endsWith(".class")) { try { var wrapper = ClassWrapper.from(new ClassReader(stream)); classes.put(wrapper.getName(), wrapper); classpath.put(wrapper.getName(), wrapper); } catch (Throwable t) { RadonLogger.warn(String.format("Error while loading input class: \"%s\" (loading as resources instead)", currentEntry.getName())); resources.put(currentEntry.getName(), IOUtils.toByteArray(stream)); } } else { resources.put(currentEntry.getName(), IOUtils.toByteArray(stream)); } } } } } catch (ZipException e) { throw new PreventableRadonException("Input \"" + file.getAbsolutePath() + "\" couldn't be loaded as a ZIP. (" + e.getMessage() + ")"); } catch (IOException e) { throw new PreventableRadonException("Input \"" + file.getAbsolutePath() + "\" couldn't be due to an IO error. (" + e.getMessage() + ")"); } } public Map getClasses() { return classes; } public Map getClasspath() { return classpath; } public Map getResources() { return resources; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/JarWriter.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils; import xyz.itzsomebody.radon.Radon; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.config.ObfConfig; import xyz.itzsomebody.radon.exceptions.FatalRadonException; import xyz.itzsomebody.radon.exceptions.PreventableRadonException; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashSet; import java.util.zip.CRC32; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class JarWriter { private int fakeIndex; public void write(String path) { var radon = Radon.getInstance(); var level = radon.config.compressionLevel; var store = radon.config.useStore; var corruptCrcs = radon.config.corruptCrcs; var antiExtraction = radon.config.antiExtraction; var fakeEntries = radon.config.fakeDuplicateEntries; if (corruptCrcs && store) { // fixme: maybe check this when loading config so people don't get annoyed that this wasn't checked until jar write throw new PreventableRadonException("Cannot use store and corrupt_crcs together"); } var classes = radon.getClasses(); var resources = radon.getResources(); RadonLogger.info(String.format("Writing output to \"%s\"", path)); var file = new File(path); if (file.exists()) { RadonLogger.info(String.format("Output already exists! Backed up to \"%s\"", IOUtils.renameExistingFile(file))); } try { var stream = new ZipOutputStream(new FileOutputStream(file)); stream.setLevel(level); if (fakeEntries > 0) { disableNameCache(stream); } if (store) { stream.setMethod(ZipOutputStream.STORED); stream.setLevel(Deflater.NO_COMPRESSION); } if (corruptCrcs) { injectCrcCorrupter(stream); } classes.forEach(((name, wrapper) -> { try { // The fact that this incredibly stupid but simple anti-extraction trick works simply blows my mind var entry = new ZipEntry(wrapper.getName() + ".class" + (antiExtraction ? "/" : "")); var data = wrapper.toByteArray(); writeEntry(stream, entry, data, store); if (antiExtraction) { writeAntiExtractionEntries(stream, entry.getName(), store); } if (fakeEntries > 0) { for (int i = 0; i < fakeEntries; i++) { var fakeEntry = new ZipEntry(entry.getName()); var fakeData = RandomUtils.randomBytes(); writeEntry(stream, fakeEntry, fakeData, store); if (antiExtraction) { writeAntiExtractionEntries(stream, fakeEntry.getName(), store); } } } } catch (Throwable t) { RadonLogger.warn(String.format("An error happened while writing class \"%s\"", name)); if (RadonConstants.VERBOSE) { t.printStackTrace(); } } })); resources.forEach((name, data) -> { try { writeEntry(stream, new ZipEntry(name), data, store); } catch (IOException ioe) { RadonLogger.warn(String.format("An IO error happened while writing resource \"%s\"", name)); if (RadonConstants.VERBOSE) { ioe.printStackTrace(); } } }); stream.setComment(radon.config.zipComment); stream.close(); } catch (IOException ioe) { if (RadonConstants.VERBOSE) { ioe.printStackTrace(); } throw new FatalRadonException("An IO error happened while writing output: " + ioe.getMessage()); } } private void writeAntiExtractionEntries(ZipOutputStream stream, String name, boolean store) throws IOException { // index entry var localIndex = fakeIndex++; var indexBytes = new byte[]{ // Completely unnecessary, but fun so why not lol (byte) localIndex, (byte) (localIndex >>> 8), (byte) (localIndex >>> 16), (byte) (localIndex >>> 24) }; writeEntry(stream, new ZipEntry(name + "index"), indexBytes, store); // name entry writeEntry(stream, new ZipEntry(name + "name"), name.substring(0, name.length() - 1).getBytes(StandardCharsets.UTF_8), store); // data_offset entry var randomInt = RandomUtils.randomInt(); var randomIntBytes = new byte[]{ // lmao, here we go again (byte) randomInt, (byte) (randomInt >>> 8), (byte) (randomInt >>> 16), (byte) (randomInt >>> 24) }; writeEntry(stream, new ZipEntry(name + "data_offset"), randomIntBytes, store); } private void writeEntry(ZipOutputStream stream, ZipEntry entry, byte[] data, boolean store) throws IOException { if (store) { populateStoredEntryInfo(entry, data); } stream.putNextEntry(entry); stream.write(data); stream.closeEntry(); } private void disableNameCache(ZipOutputStream stream) { // For reasons beyond my comprehension, this is 100% legal to do try { var clazz = ZipOutputStream.class; var field = clazz.getDeclaredField("names"); field.setAccessible(true); field.set(stream, new HashSet<>(0) { @Override public boolean add(Object o) { // lol git rekt return true; } }); } catch (NoSuchFieldException | IllegalAccessException e) { throw new FatalRadonException("Error while attempting to disable ZipOutputString name cache: " + e.toString()); } } private void injectCrcCorrupter(ZipOutputStream stream) { // tl;dr: "oh man the zip format is really f***ed" // ~samczsun try { var clazz = ZipOutputStream.class; var field = clazz.getDeclaredField("crc"); field.setAccessible(true); field.set(stream, new CRC32() { @Override public void update(byte[] b, int off, int len) { // Don't update the CRC } @Override public long getValue() { return RandomUtils.randomLong(0xFFFFFFFFL); } }); } catch (NoSuchFieldException | IllegalAccessException e) { throw new FatalRadonException("Error while attempting to inject CRC corrupter: " + e.toString()); } } private void populateStoredEntryInfo(ZipEntry entry, byte[] data) { var crc = new CRC32(); crc.update(data); entry.setCrc(crc.getValue()); entry.setSize(data.length); entry.setCompressedSize(data.length); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/RandomUtils.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils; import java.util.concurrent.ThreadLocalRandom; public class RandomUtils { private static ThreadLocalRandom instance() { return ThreadLocalRandom.current(); } // -------- // Integers // -------- public static int randomInt(int origin, int bound) { return instance().nextInt(origin, bound); } public static int randomInt(int bound) { return instance().nextInt(bound); } public static int randomInt() { return instance().nextInt(); } // ----- // Longs // ----- public static long randomLong(long origin, long bound) { return instance().nextLong(origin, bound); } public static long randomLong(long bound) { return instance().nextLong(bound); } public static long randomLong() { return instance().nextLong(); } // ------ // Floats // ------ public static float randomFloat(float origin, float bound) { if (origin >= bound) { throw new IllegalArgumentException("bound must be greater than origin"); } float r = (float)((randomInt()) >>> 8) * 5.9604645E-8F; if (origin < bound) { r = r * (bound - origin) + origin; if (r >= bound) { r = Float.intBitsToFloat(Float.floatToIntBits(bound) - 1); } } return r; } public static float randomFloat(float bound) { if (bound <= 0.0F) { throw new IllegalArgumentException("bound must be positive"); } float r = (float)((randomInt()) >>> 8) * 5.9604645E-8F; return r < bound ? r : Float.intBitsToFloat(Float.floatToIntBits(bound) - 1); } public static float randomFloat() { return instance().nextFloat(); } // -------- // Doubles // -------- public static double randomDouble(double origin, double bound) { return instance().nextDouble(origin, bound); } public static double randomDouble(double bound) { return instance().nextDouble(bound); } public static double randomDouble() { return instance().nextDouble(); } // ----- // Misc. // ----- public static boolean randomBoolean() { return instance().nextBoolean(); } public static byte[] randomBytes(int length) { var arr = new byte[length]; instance().nextBytes(arr); return arr; } public static byte[] randomBytes() { var arr = new byte[randomInt(0xFFFF)]; instance().nextBytes(arr); return arr; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/ASMUtils.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import xyz.itzsomebody.radon.exceptions.FatalRadonException; public class ASMUtils { public static AbstractInsnNode getNumberInsn(int number) { if (number >= -1 && number <= 5) return new InsnNode(number + 3); else if (number >= -128 && number <= 127) return new IntInsnNode(Opcodes.BIPUSH, number); else if (number >= -32768 && number <= 32767) return new IntInsnNode(Opcodes.SIPUSH, number); else return new LdcInsnNode(number); } public static AbstractInsnNode getNumberInsn(long number) { if (number == 0L || number == 1L) return new InsnNode((int) (number + 9)); else return new LdcInsnNode(number); } public static AbstractInsnNode getNumberInsn(float number) { if (number == 0F || number == 1F || number == 2F) { return new InsnNode((int) (number + 11)); } else { return new LdcInsnNode(number); } } public static AbstractInsnNode getNumberInsn(double number) { if (number == 0D || number == 1D) return new InsnNode((int) (number + 14)); else return new LdcInsnNode(number); } public static int getIntegerFromInsn(AbstractInsnNode insn) { int opcode = insn.getOpcode(); if (opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) { return opcode - 3; } else if (insn instanceof IntInsnNode && insn.getOpcode() != Opcodes.NEWARRAY) { return ((IntInsnNode) insn).operand; } else if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof Integer) { return (Integer) ((LdcInsnNode) insn).cst; } throw new FatalRadonException("Attempted to get integer constant from " + insn.getOpcode() + " : " + insn); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/ClassWrapper.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; import xyz.itzsomebody.radon.Radon; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.config.ObfConfig; import xyz.itzsomebody.radon.dictionaries.Dictionary; import xyz.itzsomebody.radon.utils.logging.RadonLogger; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; /** * Wrapper around {@link ClassNode}. * * @author itzsomebody */ public class ClassWrapper implements Opcodes { private static final int LIB_READER_FLAGS = ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE; private static final int INPUT_READER_FLAGS = ClassReader.SKIP_FRAMES; private static final int CP_COUNT_OFFSET = 0x4 + 0x2 + 0x2; // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.1 private ClassNode classNode; private final String originalName; private final boolean libraryNode; private final List methods; private final List fields; private final List parents = new ArrayList<>(); private final List children = new ArrayList<>(); public List utf8Consts = new ArrayList<>() { { add("RADON" + RadonConstants.VERSION); } }; public ClassWrapper(ClassReader reader, boolean libraryNode) { var classNode = new ClassNode(); reader.accept(classNode, libraryNode ? LIB_READER_FLAGS : INPUT_READER_FLAGS); this.classNode = classNode; this.originalName = classNode.name; this.libraryNode = libraryNode; this.methods = MethodWrappers.from(this); this.fields = FieldWrappers.from(this); } public ClassWrapper(ClassNode classNode, boolean libraryNode) { this.classNode = classNode; this.originalName = classNode.name; this.libraryNode = libraryNode; this.methods = MethodWrappers.from(this); this.fields = FieldWrappers.from(this); } // ----------------- // Getters / Setters // ----------------- public ClassNode getClassNode() { return classNode; } public void setClassNode(ClassNode classNode) { this.classNode = classNode; } public String getName() { return classNode.name; } public String getSuperName() { return classNode.superName; } public List getInterfaceNames() { return classNode.interfaces; } public String getOriginalName() { return originalName; } public boolean isLibraryNode() { return libraryNode; } public List getMethods() { return methods; } public Stream methodStream() { return getMethods().stream(); } public List getFields() { return fields; } public Stream fieldStream() { return getFields().stream(); } public List getParents() { return parents; } public List getChildren() { return children; } // ------------ // Access stuff // ------------ public void addAccessFlags(int flags) { classNode.access |= flags; } public void removeAccessFlags(int flags) { classNode.access &= ~flags; } public boolean isPublic() { return (classNode.access & ACC_PUBLIC) != 0; } public boolean isPrivate() { return (classNode.access & ACC_PRIVATE) != 0; } public boolean isProtected() { return (classNode.access & ACC_PROTECTED) != 0; } public boolean isFinal() { return (classNode.access & ACC_FINAL) != 0; } public boolean isSuper() { return (classNode.access & ACC_SUPER) != 0; } public boolean isInterface() { return (classNode.access & ACC_INTERFACE) != 0; } public boolean isAbstract() { return (classNode.access & ACC_ABSTRACT) != 0; } public boolean isSynthetic() { return (classNode.access & ACC_SYNTHETIC) != 0; } public boolean isAnnotation() { return (classNode.access & ACC_ANNOTATION) != 0; } public boolean isEnum() { return (classNode.access & ACC_ENUM) != 0; } public boolean isModule() { return (classNode.access & ACC_MODULE) != 0; } public boolean isRecord() { return (classNode.access & ACC_RECORD) != 0; } public boolean isDeprecated() { return (classNode.access & ACC_DEPRECATED) != 0; } // ----- // Misc. // ----- /** * Adds a {@link MethodNode} to this {@link ClassWrapper}. * * @param methodNode {@link MethodNode} to add. */ public void addMethod(MethodNode methodNode) { classNode.methods.add(methodNode); methods.add(MethodWrapper.from(methodNode, this)); } /** * Adds a {@link FieldNode} to this {@link ClassWrapper}. * * @param fieldNode {@link FieldNode} to add. */ public void addField(FieldNode fieldNode) { classNode.fields.add(fieldNode); fields.add(FieldWrapper.from(fieldNode, this)); } public MethodNode getMethodNode(String name, String desc) { return classNode.methods.stream().filter(methodNode -> name.equals(methodNode.name) && desc.equals(methodNode.desc)).findAny().orElse(null); } public FieldNode getFieldNode(String name, String desc) { return classNode.fields.stream().filter(fieldNode -> name.equals(fieldNode.name) && desc.equals(fieldNode.desc)).findAny().orElse(null); } public boolean containsMethodNode(String name, String desc) { return classNode.methods.stream().anyMatch(methodNode -> name.equals(methodNode.name) && desc.equals(methodNode.desc)); } public boolean containsFieldNode(String name, String desc) { return classNode.fields.stream().anyMatch(fieldNode -> name.equals(fieldNode.name) && desc.equals(fieldNode.desc)); } public String generateNextAllowedMethodName(Dictionary dictionary, String desc) { String name = dictionary.next(); while (containsMethodNode(name, desc)) { name = dictionary.next(); } return name; } public String generateNextAllowedFieldName(Dictionary dictionary, String desc) { String name = dictionary.next(); while (containsFieldNode(name, desc)) { name = dictionary.next(); } return name; } /** * Returns true if the class allows dynamic constants (Java 11 and above). */ public boolean allowsConstDy() { return (classNode.version >= V11) && (classNode.version != V1_1); } /** * Returns true if this class allows invokedynamic instructions (Java 7 and above). */ public boolean allowsIndy() { return (classNode.version >= V1_7) && (classNode.version != V1_1); } /** * Returns true if this class allows JSR and RET instructions (Java 5 and below). */ public boolean allowsJsr() { return (classNode.version <= V1_5) || (classNode.version == V1_1); } public boolean hasVisibleAnnotations() { return classNode.visibleAnnotations != null && classNode.visibleAnnotations.size() > 0; } /** * Returns the count of the constant pool of the classfile this {@link ClassWrapper} represents. *

* This is done by writing the class bytes via {@link ClassWriter} with flags set to 0. The constant pool count is * then manually constructed by directly accessing the relevant offsets. This is computationally expensive and should * be done sparingly */ public int computePoolCount() { // Hopefully setting flags to 0 doesn't affect CP count // If it does then pepega var writer = new ClassWriter(0); utf8Consts.forEach(writer::newUTF8); classNode.accept(writer); // Grab byte array var bytes = writer.toByteArray(); // Construct unsigned short // todo: check to make sure this isn't broken return ((bytes[CP_COUNT_OFFSET] & 0xFF) << 8) | (bytes[CP_COUNT_OFFSET + 1] & 0xFF); } public void addUtf8Const(String s) { utf8Consts.add(s); } /** * Converts the class this {@link ClassWrapper} represents into a byte array. */ public byte[] toByteArray() { var attemptMaxs = Radon.getInstance().config.attemptComputeMaxs; ClassWriter classWriter = new RadonClassWriter(ClassWriter.COMPUTE_FRAMES); try { // Write all non-essential (manually made) entries first utf8Consts.forEach(classWriter::newUTF8); // Do the rest classNode.accept(classWriter); return classWriter.toByteArray(); } catch (Throwable t) { if (attemptMaxs) { RadonLogger.warn(String.format("Error writing class %s. Skipping frames (might cause runtime errors).", classNode.name + ".class")); t.printStackTrace(System.out); classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); // Write all non-essential (manually inserted) utf8 entries first utf8Consts.forEach(classWriter::newUTF8); // Do the rest classNode.accept(classWriter); return classWriter.toByteArray(); } else { throw t; } } } public static ClassWrapper from(ClassReader reader) { return new ClassWrapper(reader, false); } public static ClassWrapper fromLib(ClassReader reader) { return new ClassWrapper(reader, true); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/FieldWrapper.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.FieldNode; /** * Wrapper around {@link FieldNode}. * * @author itzsomebody */ public class FieldWrapper implements Opcodes { private FieldNode fieldNode; private final String originalName; private final String originalType; private final ClassWrapper owner; public FieldWrapper(FieldNode fieldNode, ClassWrapper owner) { this.fieldNode = fieldNode; this.originalName = fieldNode.name; this.originalType = fieldNode.desc; this.owner = owner; } // ----------------- // Getters / Setters // ----------------- public FieldNode getFieldNode() { return fieldNode; } public void setFieldNode(FieldNode fieldNode) { this.fieldNode = fieldNode; } public String getOriginalName() { return originalName; } public String getOriginalType() { return originalType; } public ClassWrapper getOwner() { return owner; } // ------------ // Access stuff // ------------ public void addAccessFlags(int flags) { fieldNode.access |= flags; } public void removeAccessFlags(int flags) { fieldNode.access &= ~flags; } public boolean isPublic() { return (ACC_PUBLIC & fieldNode.access) != 0; } public boolean isPrivate() { return (ACC_PRIVATE & fieldNode.access) != 0; } public boolean isProtected() { return (ACC_PROTECTED & fieldNode.access) != 0; } public boolean isStatic() { return (ACC_STATIC & fieldNode.access) != 0; } public boolean isFinal() { return (ACC_FINAL & fieldNode.access) != 0; } public boolean isVolatile() { return (ACC_PUBLIC & fieldNode.access) != 0; } public boolean isTransient() { return (ACC_PUBLIC & fieldNode.access) != 0; } public boolean isSynthetic() { return (ACC_SYNTHETIC & fieldNode.access) != 0; } public boolean isDeprecated() { return (ACC_DEPRECATED & fieldNode.access) != 0; } // ----- // Misc. // ----- public static FieldWrapper from(FieldNode FieldNode, ClassWrapper owner) { return new FieldWrapper(FieldNode, owner); } public boolean hasVisibleAnnotations() { return fieldNode.visibleAnnotations != null && fieldNode.visibleAnnotations.size() > 0; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/FieldWrappers.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import java.util.ArrayList; import java.util.List; public class FieldWrappers { public static List from(ClassWrapper classWrapper) { var classNode = classWrapper.getClassNode(); var fieldWrappers = new ArrayList(); classNode.fields.forEach(fieldNode -> fieldWrappers.add(FieldWrapper.from(fieldNode, classWrapper))); return fieldWrappers; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/MethodWrapper.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.CodeSizeEvaluator; import org.objectweb.asm.tree.MethodNode; /** * Wrapper around {@link MethodNode}. * * @author itzsomebody */ public class MethodWrapper implements Opcodes { /* * From https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.3 * * Note that even though the specification lists an unsigned 32-bit integer size for code_length, the verifier gets * mad if any method has a code_length > 0xFFFF */ private static final int MAX_CODE_SIZE = 0xFFFF; private MethodNode methodNode; private final String originalName; private final String originalDescriptor; private final ClassWrapper owner; public MethodWrapper(MethodNode methodNode, ClassWrapper owner) { this.methodNode = methodNode; this.originalName = methodNode.name; this.originalDescriptor = methodNode.desc; this.owner = owner; } // ----------------- // Getters / Setters // ----------------- public MethodNode getMethodNode() { return methodNode; } public void setMethodNode(MethodNode methodNode) { this.methodNode = methodNode; } public String getOriginalName() { return originalName; } public String getOriginalDescriptor() { return originalDescriptor; } public ClassWrapper getOwner() { return owner; } // ------------ // Access stuff // ------------ public void addAccessFlags(int flags) { methodNode.access |= flags; } public void removeAccessFlags(int flags) { methodNode.access &= ~flags; } public boolean isPublic() { return (ACC_PUBLIC & methodNode.access) != 0; } public boolean isPrivate() { return (ACC_PRIVATE & methodNode.access) != 0; } public boolean isProtected() { return (ACC_PROTECTED & methodNode.access) != 0; } public boolean isStatic() { return (ACC_STATIC & methodNode.access) != 0; } public boolean isFinal() { return (ACC_FINAL & methodNode.access) != 0; } public boolean isSynchronized() { return (ACC_SYNCHRONIZED & methodNode.access) != 0; } public boolean isBridge() { return (ACC_BRIDGE & methodNode.access) != 0; } public boolean isVarargs() { return (ACC_VARARGS & methodNode.access) != 0; } public boolean isNative() { return (ACC_NATIVE & methodNode.access) != 0; } public boolean isAbstract() { return (ACC_ABSTRACT & methodNode.access) != 0; } public boolean isStrict() { return (ACC_STRICT & methodNode.access) != 0; } public boolean isSynthetic() { return (ACC_SYNTHETIC & methodNode.access) != 0; } public boolean isMandated() { return (ACC_MANDATED & methodNode.access) != 0; } public boolean isDeprecated() { return (ACC_DEPRECATED & methodNode.access) != 0; } // ----- // Misc. // ----- public boolean hasInstructions() { return methodNode.instructions.size() > 0; } public boolean hasVisibleAnnotations() { return methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.size() > 0; } public int getCodeSize() { CodeSizeEvaluator evaluator = new CodeSizeEvaluator(null); methodNode.accept(evaluator); return evaluator.getMaxSize(); } public int getLeewaySize() { return MAX_CODE_SIZE - getCodeSize(); } public int allocateLocalVar(boolean twoWords) { methodNode.maxLocals += (twoWords ? 2 : 1); return methodNode.maxLocals - 1; } public static MethodWrapper from(MethodNode methodNode, ClassWrapper owner) { return new MethodWrapper(methodNode, owner); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/MethodWrappers.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import java.util.ArrayList; import java.util.List; public class MethodWrappers { public static List from(ClassWrapper classWrapper) { var classNode = classWrapper.getClassNode(); var methodWrappers = new ArrayList(); classNode.methods.forEach(methodNode -> methodWrappers.add(MethodWrapper.from(methodNode, classWrapper))); return methodWrappers; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/RadonClassWriter.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.ClassWriter; import xyz.itzsomebody.radon.Radon; import java.util.ArrayDeque; import java.util.HashSet; /** * Custom-implemented version of {@link ClassWriter} which doesn't use the internal JVM classpath when computing * stackmap frames. * * TODO: Perhaps consider creating fully-worked out hierarchies for JVM runtime classes so we don't have to keep checking huge jars * TODO: Implement shadow classes * * @author itzsomebody */ public class RadonClassWriter extends ClassWriter { private static final Radon radon = Radon.getInstance(); public RadonClassWriter(int flags) { super(flags); } @Override protected String getCommonSuperClass(final String type1, final String type2) { if ("java/lang/Object".equals(type1) || "java/lang/Object".equals(type2)) return "java/lang/Object"; String first = deriveCommonSuperName(type1, type2); String second = deriveCommonSuperName(type2, type1); if (!"java/lang/Object".equals(first)) { return first; } if (!"java/lang/Object".equals(second)) { return second; } return getCommonSuperClass(radon.getClasspathWrapper(type1).getSuperName(), radon.getClasspathWrapper(type2).getSuperName()); } private String deriveCommonSuperName(final String type1, final String type2) { ClassWrapper first = radon.getClasspathWrapper(type1); ClassWrapper second = radon.getClasspathWrapper(type2); if (isAssignableFrom(type1, type2)) { return type1; } else if (isAssignableFrom(type2, type1)) { return type2; } else if (first.isInterface() || second.isInterface()) { return "java/lang/Object"; } else { String temp; do { temp = first.getSuperName(); first = radon.getClasspathWrapper(temp); } while (!isAssignableFrom(temp, type2)); return temp; } } private boolean isAssignableFrom(String type1, String type2) { if ("java/lang/Object".equals(type1)) { return true; } if (type1.equals(type2)) { return true; } ClassWrapper first = radon.getClasspathWrapper(type1); radon.getClasspathWrapper(type2); // Ensure type2 was loaded at some point var allChildren = new HashSet(); var toProcess = new ArrayDeque(); first.getChildren().forEach(child -> { toProcess.add(child.getName()); }); while (!toProcess.isEmpty()) { String next = toProcess.poll(); if (allChildren.add(next)) { ClassWrapper temp = radon.getClasspathWrapper(next); temp.getChildren().forEach(child -> { toProcess.add(child.getName()); }); } } return allChildren.contains(type2); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/RadonRemapper.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.commons.SimpleRemapper; import java.util.Map; public class RadonRemapper extends SimpleRemapper { public RadonRemapper(Map mappings) { super(mappings); } @Override public String mapFieldName(String owner, String name, String descriptor) { String remappedName = map(owner + '.' + name + ' ' + descriptor); return (remappedName != null) ? remappedName : name; } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/asm/ResourceNameRemapper.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.asm; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.Map; // Stupid way remapping resource names, but works for the most part // If you want to do an *actual* job of this, you should use the SourceInterpreter to update strings arguments // to methods that grab resources by their name public class ResourceNameRemapper extends ClassVisitor { private final Map mappings; private final String internalName; public ResourceNameRemapper(ClassVisitor visitor, Map mappings, String internalName) { this(/* latest api */ Opcodes.ASM9, visitor, mappings, internalName); } protected ResourceNameRemapper(int api, ClassVisitor visitor, Map mappings, String internalName) { super(api, visitor); this.mappings = mappings; this.internalName = internalName; } @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { return new ResourceNameMethodRemapper(super.visitMethod( access, name, descriptor, signature, exceptions )); } class ResourceNameMethodRemapper extends MethodVisitor { ResourceNameMethodRemapper(MethodVisitor visitor) { this(/* latest api */ Opcodes.ASM9, visitor); } ResourceNameMethodRemapper(int api, MethodVisitor visitor) { super(api, visitor); } @Override public void visitLdcInsn(Object value) { if (value instanceof String) { String strValue = (String) value; String fullResourcePath; if (strValue.startsWith("/")) { // JAR root case fullResourcePath = strValue.substring(1); } else { // relative path case int index = internalName.lastIndexOf('/'); if (index == -1) { fullResourcePath = ""; // Already at root } else { fullResourcePath = internalName.substring(0, index + 1) + strValue; } } if (mappings.containsKey(fullResourcePath)) { super.visitLdcInsn(mappings.get(fullResourcePath)); } else { super.visitLdcInsn(value); } return; } super.visitLdcInsn(value); } } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/logging/RadonConsoleHandler.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.logging; import xyz.itzsomebody.radon.RadonConstants; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Formatter; import java.util.logging.LogRecord; import java.util.logging.StreamHandler; /** * A {@link StreamHandler} which outputs to stdout ({@link System#out}). * * @author itzsomebody */ public class RadonConsoleHandler extends StreamHandler { /** * Constructs a {@link StreamHandler} which outputs to stdout ({@link System#out}). *

* The {@link String} pushed into stdout is composed of a timestamp, level, and message. */ public RadonConsoleHandler() { super(System.out, new Formatter() { @Override public String format(final LogRecord record) { var formatStr = "[%s] %s: %s\n"; var dateStr = new SimpleDateFormat(RadonConstants.LOG_TIMESTAMP_FORMAT).format(new Date(record.getMillis())); var levelName = record.getLevel().getName(); var formattedMsg = formatMessage(record); return String.format(formatStr, dateStr, levelName, formattedMsg); } }); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/java/xyz/itzsomebody/radon/utils/logging/RadonLogger.java ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2020 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package xyz.itzsomebody.radon.utils.logging; import xyz.itzsomebody.radon.RadonConstants; import xyz.itzsomebody.radon.RadonMain; import java.util.logging.Logger; /** * Wrapper around {@link Logger} to push messages into stdout ({@link System#out}). Parent handler inheritance is * switched off. * * @author itzsomebody */ public class RadonLogger { /** * Static instance of {@link Logger#getAnonymousLogger()}. */ private static final Logger LOGGER; static { if (RadonConstants.VERBOSE) { System.out.println("[RadonLogger] Bootstrapping logger"); } LOGGER = Logger.getLogger("RadonLogger"); if (RadonConstants.VERBOSE) { System.out.println("[RadonLogger] Created logger instance"); } LOGGER.setUseParentHandlers(false); // Avoid parent handler inheritance if (RadonConstants.VERBOSE) { System.out.println("[RadonLogger] Disabled parent handler inheritance"); } LOGGER.addHandler(new RadonConsoleHandler()); if (RadonConstants.VERBOSE) { System.out.println("[RadonLogger] Registered console handler"); } } /** * Pushes provided message into stdout ({@link System#out}) via {@link Logger#info(String)}. * * @param msg Message to output into stdout ({@link System#out}). */ public static void info(final String msg) { LOGGER.info(msg); } /** * Pushes provided message into stdout ({@link System#out}) via {@link Logger#warning(String)}. * * @param msg Message to output into stdout ({@link System#out}). */ public static void warn(final String msg) { LOGGER.warning(msg); } /** * Pushes provided message into stdout ({@link System#out}) via {@link Logger#severe(String)}. * * @param msg Message to output into stdout ({@link System#out}). */ public static void severe(final String msg) { LOGGER.severe(msg); } } ================================================ FILE: xyz.itzsomebody.radon/src/main/resources/asm-license.txt ================================================ ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2011 INRIA, France Telecom All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: xyz.itzsomebody.radon/src/main/resources/jackson-license.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: xyz.itzsomebody.radon/src/main/resources/radon-license.txt ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS ================================================ FILE: xyz.itzsomebody.radon/src/test/java/me/itzsomebody/radon/transformers/TransformersTest.java ================================================ package me.itzsomebody.radon.transformers; import org.junit.Assert; import org.junit.Test; import xyz.itzsomebody.radon.exclusions.Exclusion; import xyz.itzsomebody.radon.transformers.Transformers; import xyz.itzsomebody.radon.transformers.strings.StringTransformer; public class TransformersTest { @Test public void ensureTransformerExclusionTypeNonNull() throws Exception { for (var transformerEnum : Transformers.values()) { var transformerConstructor = transformerEnum.getTransformerClass().getConstructor(); transformerConstructor.setAccessible(true); var transformerInstance = transformerConstructor.newInstance(); // Often I'm dumb and forget to put an exclusion type Assert.assertNotNull(transformerInstance.getExclusionType()); } } @Test public void ensureTransformerConfigNameNonNull() throws Exception{ for (var transformerEnum : Transformers.values()) { var transformerConstructor = transformerEnum.getTransformerClass().getConstructor(); transformerConstructor.setAccessible(true); var transformerInstance = transformerConstructor.newInstance(); Assert.assertNotNull(transformerInstance.getConfigName()); } } @Test public void ensureTransformerExclusionTypeNameIsSameAsConfigName() throws Exception{ for (var transformerEnum : Transformers.values()) { var transformerConstructor = transformerEnum.getTransformerClass().getConstructor(); transformerConstructor.setAccessible(true); var transformerInstance = transformerConstructor.newInstance(); if (transformerInstance instanceof StringTransformer) { // Skip -- mostly likely no problem here } else { Assert.assertEquals(transformerInstance.getConfigName(), transformerInstance.getExclusionType().name().toLowerCase()); } } } } ================================================ FILE: xyz.itzsomebody.radon.template/build.gradle ================================================ /* * Radon - An open-source Java obfuscator * Copyright (C) 2021 ItzSomebody * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ plugins { id 'java' } sourceCompatibility = javaVer dependencies { testImplementation junit } ================================================ FILE: xyz.itzsomebody.radon.template/src/README.md ================================================ # Template This module contains various template classes to use with ASMifier. ================================================ FILE: xyz.itzsomebody.radon.template/src/main/java/xyz/itzsomebody/radon/templates/string/AESPCBCDecryptor.java ================================================ package xyz.itzsomebody.radon.templates.string; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; public class AESPCBCDecryptor { public static int[][] sbox; public static int[][] invSbox; public static int[] rcon; // round constants public static int[] expandedKey; // expanded key public static int[][] mcTables; // lookup tables for MixColumns static { // SBox // See https://crypto.stackexchange.com/questions/85670/need-help-understanding-math-behind-rijndael-s-box // for an explanation of how 3 generates GF[2^8] sbox = new int[0x10][0x10]; int p = 1; int q = 1; do { p = gfMult(3, p); q = gfMult(0xF6, q); int trans = q; // Affine transformation trans ^= ((q << 1) | (q >>> (8 - 1))) & 0xFF; trans ^= ((q << 2) | (q >>> (8 - 2))) & 0xFF; trans ^= ((q << 3) | (q >>> (8 - 3))) & 0xFF; trans ^= ((q << 4) | (q >>> (8 - 4))) & 0xFF; sbox[p / 16][p % 16] = (trans ^ 0x63) & 0xFF; } while (p != 1); sbox[0][0] = 0x63; // 0 is never invertible so set manually // InvSBox invSbox = new int[sbox.length][sbox.length]; for (int row = 0; row < sbox.length; row++) { for (int col = 0; col < sbox[0].length; col++) { int b = sbox[row][col]; invSbox[b >> 4][b & 0xF] = (row << 4) | col; } } // Round constants rcon = new int[10]; for (int i = 0; i < rcon.length; i++) { if (i == 0) { rcon[i] = 1; } else if (rcon[i - 1] < 0x80) { rcon[i] = 2 * rcon[i - 1]; } else if (rcon[i - 1] >= 0x80) { rcon[i] = (2 * rcon[i - 1]) ^ 0x11B; } } for (int i = 0; i < rcon.length; i++) { rcon[i] <<= 24; } // Multiplication tables for MixColumns mcTables = new int[0xF][]; mcTables[0xE] = new int[0x100]; mcTables[0xB] = new int[0x100]; mcTables[0xD] = new int[0x100]; mcTables[0x9] = new int[0x100]; for (int mult = 0; mult < mcTables.length; mult++) { if (mcTables[mult] != null) { int[] table = mcTables[mult]; for (int n = 0; n < table.length; n++) { table[n] = gfMult(mult, n); } } } } public static int subWord(int word) { int b0 = (word >> (8 * 3)) & 0xFF; int b1 = (word >> (8 * 2)) & 0xFF; int b2 = (word >> 8) & 0xFF; int b3 = word & 0xFF; return (sbox[b0 >> 4][b0 & 0xF] << 8 * 3) | (sbox[b1 >> 4][b1 & 0xF] << 8 * 2) | (sbox[b2 >> 4][b2 & 0xF] << 8) | (sbox[b3 >> 4][b3 & 0xF]); } public static void keySchedule(int[] key) { // AES-128 int R = 11; expandedKey = new int[4 * R]; for (int i = 0; i < expandedKey.length; i++) { if (i < key.length) { expandedKey[i] = key[i]; } else if (i % key.length == 0) { int b = (expandedKey[i - 1] << 8) | (expandedKey[i - 1] >>> (32 - 8)); expandedKey[i] = expandedKey[i - key.length]; expandedKey[i] ^= subWord(b); expandedKey[i] ^= rcon[i / key.length - 1]; } else { expandedKey[i] = expandedKey[i - key.length] ^ expandedKey[i - 1]; } } } public static void addRoundKey(int[][] state, int round) { for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[0].length; col++) { int rkey = expandedKey[round * state[0].length + col]; int xbyte = (rkey >> (8 * (state.length - 1) - 8 * row)) & 0xFF; state[row][col] ^= xbyte; } } } public static void invShiftRows(int[][] state) { for (int offset = 0; offset < state.length; offset++) { int[] row = state[offset]; int[] shifted = new int[row.length]; for (int i = 0; i < row.length; i++) { shifted[(i + offset) % 4] = row[i]; } state[offset] = shifted; } } public static void invSubBytes(int[][] state) { for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[row].length; col++) { int s = state[row][col]; int upper = s >> 4; int lower = s & 0xF; state[row][col] = invSbox[upper][lower]; } } } // Multiply in GF[2^8] public static int gfMult(int mult, int b) { int result = 0; for (int i = 0; i < 8; i++) { if ((mult & 0x1) != 0) { result ^= b; } mult >>= 1; int mod = 0; if ((b & 0x80) != 0) { mod = 0x11B; } b = (b << 1) ^ mod; } return result; } public static void invMixColumns(int[][] state) { for (int col = 0; col < state[0].length; col++) { int s1 = mcTables[0xE][state[0][col]] ^ mcTables[0xB][state[1][col]] ^ mcTables[0xD][state[2][col]] ^ mcTables[0x9][state[3][col]]; int s2 = mcTables[0x9][state[0][col]] ^ mcTables[0xE][state[1][col]] ^ mcTables[0xB][state[2][col]] ^ mcTables[0xD][state[3][col]]; int s3 = mcTables[0xD][state[0][col]] ^ mcTables[0x9][state[1][col]] ^ mcTables[0xE][state[2][col]] ^ mcTables[0xB][state[3][col]]; int s4 = mcTables[0xB][state[0][col]] ^ mcTables[0xD][state[1][col]] ^ mcTables[0x9][state[2][col]] ^ mcTables[0xE][state[3][col]]; state[0][col] = s1; state[1][col] = s2; state[2][col] = s3; state[3][col] = s4; } } public static void invCipher(int[][] state) { int round = 10; addRoundKey(state, round); for (round = 9; round > 0; round--) { invShiftRows(state); invSubBytes(state); addRoundKey(state, round); invMixColumns(state); } invSubBytes(state); invShiftRows(state); addRoundKey(state, round); } public static String decrypt(String input, long[] ivInts) { // Compute key based on callstack (yes we're doing this meme again) var callstack = Thread.currentThread().getStackTrace(); int[] key = new int[]{ callstack[1].getClassName().hashCode(), callstack[1].getMethodName().hashCode(), callstack[2].getClassName().hashCode(), callstack[2].getMethodName().hashCode() }; keySchedule(key); // Convert IV to correct format int[] ivBytes = new int[0x10]; for (int i = 0; i < ivInts.length; i++) { for (int j = 0; j < 8; j++) { ivBytes[i * 8 + j] = (int) ((ivInts[i] >>> (56 - j * 8)) & 0xFF); } } int[][] iv = create_state(ivBytes); // Input -> state for InvCipher int[] cipherText = design(Base64.getDecoder().decode(input)); int[][][] states = new int[cipherText.length / 16][][]; for (int i = 0; i < states.length; i++) { int[] subarray = Arrays.copyOfRange(cipherText, i * 16, (i + 1) * 16); states[i] = create_state(subarray); } // PCBC decryption alg int[][] previousBlock1 = copyBlock(states[0]); invCipher(states[0]); for (int row = 0; row < states[0].length; row++) { for (int col = 0; col < states[0][0].length; col++) { states[0][row][col] ^= iv[row][col]; previousBlock1[row][col] ^= states[0][row][col]; } } for (int i = 1; i < states.length; i++) { int[][] previousBlock2 = copyBlock(states[i]); invCipher(states[i]); int[][] state = states[i]; for (int row = 0; row < state.length; row++) { for (int col = 0; col < state[0].length; col++) { state[row][col] ^= previousBlock1[row][col]; previousBlock2[row][col] ^= state[row][col]; } } previousBlock1 = previousBlock2; } // Reconstruct bytes byte[] processed = new byte[cipherText.length]; for (int i = 0; i < states.length; i++) { int[] vector = new int[0x10]; for (int col = 0; col < states[0].length; col++) { for (int row = 0; row < states[0][0].length; row++) { vector[col * 4 + row] = states[i][row][col]; } } System.arraycopy(resign(vector), 0, processed, i * 16, vector.length); } // Remove padding int nPadBytes = processed[processed.length - 1]; byte[] message = new byte[processed.length - nPadBytes]; System.arraycopy(processed, 0, message, 0, message.length); return new String(message, StandardCharsets.UTF_8); } public static int[][] copyBlock(int[][] block) { int[][] copy = new int[block.length][block[0].length]; for (int row = 0; row < block.length; row++) { for (int col = 0; col < block[0].length; col++) { copy[row][col] = block[row][col]; } } return copy; } public static int[] design(byte[] arr) { int[] designed = new int[arr.length]; for (int i = 0; i < arr.length; i++) { designed[i] = arr[i] & 0xFF; } return designed; } public static byte[] resign(int[] arr) { byte[] signed = new byte[arr.length]; for (int i = 0; i < arr.length; i++) { signed[i] = (byte) arr[i]; } return signed; } public static int[][] create_state(int[] bytes) { int[][] state = new int[4][4]; for (int i = 0; i < bytes.length; i++) { state[i % 4][i / 4] = bytes[i]; } return state; } }