diff --git a/src/main/resources/jumbotron-image.1920e0770dc6.svg b/src/main/resources/jumbotron-image.1920e0770dc6.svg new file mode 100644 index 00000000..6afa2d4a --- /dev/null +++ b/src/main/resources/jumbotron-image.1920e0770dc6.svg @@ -0,0 +1,310 @@ + + + + diff --git a/src/main/resources/pyscripts/check_hash b/src/main/resources/pyscripts/check_hash index b81af0a3..2aef3805 100644 --- a/src/main/resources/pyscripts/check_hash +++ b/src/main/resources/pyscripts/check_hash @@ -1,3 +1,9 @@ -main 96c29c93a496e6dbd73414157005a3f8 -removeComments 3c77e514c7a6095124abc318b6093150 -taintAnalysis 19202341a70ad86d09009a4653ca79a8 +stringSearch 0874410948a51042828b856410115e86 +main 50161042ab273d6dbf31845f33513254 +stringEncrypt f41b4195de585aac72cdd0fc7285f48c +keyObfuscate 676fb4f92742441da501bbc27038a204 +stringObfuscate bf859f2f4f0c9117e99876726bfeed21 +stringInsert 0983fd34b3420bc1c654304cbc8c267c +removeComments a7b260d4aa940c7cc818c321167cd1de +taintAnalysis 7e55b0e079c4b4bfe3b88e980de0d7a6 +obfuscateTool bc032265f457512a38a4222dd1f7d085 diff --git a/src/main/resources/pyscripts/create_hash.py b/src/main/resources/pyscripts/create_hash.py index ddf968a7..3332ee17 100644 --- a/src/main/resources/pyscripts/create_hash.py +++ b/src/main/resources/pyscripts/create_hash.py @@ -9,6 +9,7 @@ def calculate_md5(file_path): md5_hash.update(byte_block) return md5_hash.hexdigest() + def hash_files_in_directory(directory_path, exclude_file='create_hash.py', output_file='check_hash'): """디렉토리 내의 .py 파일들의 MD5 해시값을 계산하고 결과를 output_file에 저장합니다.""" with open(directory_path + output_file, 'w') as output: diff --git a/src/main/resources/pyscripts/keyDecrypt.java b/src/main/resources/pyscripts/keyDecrypt.java new file mode 100644 index 00000000..1227e5ea --- /dev/null +++ b/src/main/resources/pyscripts/keyDecrypt.java @@ -0,0 +1,66 @@ +public static List keySchedule(byte[] key, int rounds) throws NoSuchAlgorithmException { + List schedule = new ArrayList<>(); + schedule.add(key); + + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + for (int i = 1; i < rounds; i++) { + byte[] newKey = digest.digest(schedule.get(schedule.size() - 1)); + schedule.add(Arrays.copyOf(newKey, 16)); // 16바이트로 제한 + } + return schedule; + } + + public static byte[] inverseFeistelNetwork(byte[] block, byte[] roundKey) { + byte[] left = Arrays.copyOfRange(block, 0, 8); + byte[] right = Arrays.copyOfRange(block, 8, 16); + byte[] f_result = new byte[8]; + for (int i = 0; i < 8; i++) { + f_result[i] = (byte) (left[i] ^ roundKey[i]); + } + byte[] newLeft = new byte[8]; + for (int i = 0; i < 8; i++) { + newLeft[i] = (byte) (right[i] ^ f_result[i]); + } + return concatenate(newLeft, left); + } + + public static byte[] keyDecryptAlg(byte[] data, byte[] key, int rounds) throws NoSuchAlgorithmException { + List keySched = keySchedule(key, rounds); + byte[] decrypted = new byte[data.length]; + for (int i = 0; i < data.length; i += 16) { + byte[] block = Arrays.copyOfRange(data, i, i + 16); + for (int j = keySched.size() - 1; j >= 0; j--) { + block = inverseFeistelNetwork(block, keySched.get(j)); + } + System.arraycopy(block, 0, decrypted, i, 16); + } + return removePadding(decrypted); + } + + public static byte[] concatenate(byte[] a, byte[] b) { + byte[] result = new byte[a.length + b.length]; + System.arraycopy(a, 0, result, 0, a.length); + System.arraycopy(b, 0, result, a.length, b.length); + return result; + } + + public static byte[] removePadding(byte[] data) { + int i = data.length - 1; + while (i >= 0 && data[i] == 0) { + i--; + } + return Arrays.copyOf(data, i + 1); + } + + public static byte[] keyDecrypt(String key, String key2) throws NoSuchAlgorithmException { + byte[] deckey = Base64.getDecoder().decode(key); + byte[] deckey2 = Base64.getDecoder().decode(key2); + + byte[] decrypted_key = keyDecryptAlg(deckey, deckey2, 16); + + return decrypted_key; + } + + + + diff --git a/src/main/resources/pyscripts/keyObfuscate.py b/src/main/resources/pyscripts/keyObfuscate.py new file mode 100644 index 00000000..eaed7408 --- /dev/null +++ b/src/main/resources/pyscripts/keyObfuscate.py @@ -0,0 +1,61 @@ +import hashlib + +class KeyObfuscate: + def __init__(self, aes_key, enc_key): + self.enc_aes_key = self.__key_encrypt(aes_key, enc_key) + + + def __key_schedule(self, key, rounds): + schedule = [key] + for i in range(1, rounds): + new_key = hashlib.sha256(schedule[-1]).digest() + schedule.append(new_key[:16]) # 16바이트로 제한 + return schedule + + + def __feistel_network(self, block, round_key): + left, right = block[:8], block[8:] + f_result = bytes(a ^ b for a, b in zip(right, round_key[:8])) + new_right = bytes(a ^ b for a, b in zip(left, f_result)) + return right + new_right + + + def __inverse_feistel_network(self, block, round_key): + left, right = block[:8], block[8:] + f_result = bytes(a ^ b for a, b in zip(left, round_key[:8])) + new_left = bytes(a ^ b for a, b in zip(right, f_result)) + return new_left + left + + + def __encrypt(self, data, key, rounds=16): + key_sched = self.__key_schedule(key, rounds) + encrypted = bytearray() + for i in range(0, len(data), 16): + block = data[i:i+16] + if len(block) < 16: + block = block.ljust(16, b'\x00') + for round_key in key_sched: + block = self.__feistel_network(block, round_key) + encrypted.extend(block) + return bytes(encrypted) + + + def __decrypt(self, data, key, rounds=16): + key_sched = self.__key_schedule(key, rounds) + decrypted = bytearray() + for i in range(0, len(data), 16): + block = data[i:i+16] + for round_key in reversed(key_sched): + block = self.__inverse_feistel_network(block, round_key) + decrypted.extend(block) + return bytes(decrypted).rstrip(b'\x00') + + + def __key_encrypt(self, aes_key, key2): + enc2_aes_key = self.__encrypt(aes_key, key2) + return enc2_aes_key + + + def __key_decrypt(self, enc2_aes_key, key2): + enc_aes_key = self.__decrypt(enc2_aes_key, key2) + return enc_aes_key \ No newline at end of file diff --git a/src/main/resources/pyscripts/main.py b/src/main/resources/pyscripts/main.py index 3c46f9a6..a88a106c 100644 --- a/src/main/resources/pyscripts/main.py +++ b/src/main/resources/pyscripts/main.py @@ -2,6 +2,8 @@ from taintAnalysis import taintAnalysis from removeComments import removeComments +from stringObfuscate import stringObfuscate + def create_taint_result(output_path, flows): with open(output_path + "result.txt", 'w', encoding='utf-8') as file: # 결과 파일 생성 @@ -32,6 +34,7 @@ def main(java_folder_path, output_folder): create_taint_result(output_folder, tainted.flows) removeComments(output_folder) + stringObfuscate(output_folder) if __name__ == '__main__': diff --git a/src/main/resources/pyscripts/obfuscateTool.py b/src/main/resources/pyscripts/obfuscateTool.py new file mode 100644 index 00000000..30e7e28e --- /dev/null +++ b/src/main/resources/pyscripts/obfuscateTool.py @@ -0,0 +1,32 @@ +import random +import javalang +import os + +class obfuscateTool : + def random_class(class_list, random_count): + leng = len(class_list) + random_indices = [random.randint(0, leng - 1) for _ in range(random_count)] + + random_class = [class_list[i] for i in random_indices] + + return random_class + + + def parse_java_files(folder_path): + java_files = [] + + for root, _, files in os.walk(folder_path): + for file_name in files: + if file_name.endswith('.java'): + file_path = os.path.join(root, file_name) + with open(file_path, 'r', encoding='utf-8') as file: + source_code = file.read() + try: + tree = javalang.parse.parse(source_code) + java_files.append((file_path, tree, source_code)) + except javalang.parser.JavaSyntaxError as e: + print(f"Syntax error in file {file_path}: {e}") + except Exception as e: + print(f"Error parsing file {file_path}: {e}") + return java_files + diff --git a/src/main/resources/pyscripts/removeComments.py b/src/main/resources/pyscripts/removeComments.py index e037149a..87295bc1 100644 --- a/src/main/resources/pyscripts/removeComments.py +++ b/src/main/resources/pyscripts/removeComments.py @@ -1,37 +1,27 @@ from re import sub -import os + +from obfuscateTool import obfuscateTool + class removeComments: def __init__(self, project_path): print("주석 제거 작업 시작...") - self.__find_java_files(project_path) + self.__process_file(project_path) print("주석 제거 완료.") + def __process_file(self, project_path): + java_files = obfuscateTool.parse_java_files(project_path) - def __find_java_files(self, project_path): - for root, _, files in os.walk(project_path): - for file in files: - if file.endswith('.java'): - file_path = os.path.join(root, file) - self.__process_file(file_path) - - - def __process_file(self, file_path): - with open(file_path, 'r', encoding='utf-8') as file: - java_code = file.read() - - cleaned_code = self.__remove_comments(java_code) + for path, tree, source_code in java_files: + cleaned_code = self.__remove_comments(source_code) + with open(path, 'w', encoding='utf-8') as file: + file.write(cleaned_code) + print(f"Processed: {path}") - with open(file_path, 'w', encoding='utf-8') as file: - file.write(cleaned_code) - - print(f"Processed: {file_path}") - - def __remove_comments(self, java_code): # 문자열 내부의 주석 기호를 임시로 대체 code = sub(r'(".*?(? 1 else array_declaration + key_declaration_list = key_declaration_list.reverse() if len(key_declaration_list) > 1 else key_declaration_list + + decrypt_code = f""" + static{{try {{Class decryptorClass1 = Class.forName("{self.key_decrypt[0]}.{self.key_decrypt[1]}"); + Method decryptMethod1 = decryptorClass1.getMethod("keyDecrypt", String.class, String.class); + Class decryptorClass2 = Class.forName("{self.str_decrypt[0]}.{self.str_decrypt[1]}"); + Method decryptMethod2 = decryptorClass2.getMethod("stringDecrypt", String.class, byte[].class); + for (int i = 0; i < STRING_LITERALS.length; i++) + {{STRING_LITERALS[i] = + (String) decryptMethod2.invoke(null, STRING_LITERALS[i], + (byte[]) decryptMethod1.invoke(null,ENC_ENCRYPTION_KEY, + ENCRYPTION_KEY)); + }}}} catch (Exception e) {{}}}} + """ + + for i,pos in enumerate(classes_pos): + lines.insert(pos,array_declaration[i]) + lines.insert(pos+1,key_declaration_list[i]) + lines.insert(pos+2,decrypt_code) + + reflection = 'import java.lang.reflect.Method;' + if reflection not in lines: + lines.insert(1, reflection) + + code = '\n'.join(lines) + + return code \ No newline at end of file diff --git a/src/main/resources/pyscripts/stringObfuscate.py b/src/main/resources/pyscripts/stringObfuscate.py new file mode 100644 index 00000000..7bf31ef3 --- /dev/null +++ b/src/main/resources/pyscripts/stringObfuscate.py @@ -0,0 +1,14 @@ +from stringSearch import stringSearch +from stringEncrypt import stringEncrypt +from stringInsert import stringInsert + +from obfuscateTool import obfuscateTool + +class stringObfuscate : + def __init__(self, output_folder) : + search_str = stringSearch(output_folder) + random_classes = obfuscateTool.random_class(search_str.class_names, 2) + + encrypt_str = stringEncrypt(search_str.Literals) + + insert_str = stringInsert(search_str.Literals,encrypt_str.encrypted_Literals,random_classes,output_folder) \ No newline at end of file diff --git a/src/main/resources/pyscripts/stringSearch.py b/src/main/resources/pyscripts/stringSearch.py new file mode 100644 index 00000000..774298f6 --- /dev/null +++ b/src/main/resources/pyscripts/stringSearch.py @@ -0,0 +1,32 @@ +import javalang + +from obfuscateTool import obfuscateTool + +class stringSearch: + def __init__(self, java_folder_path): + self.class_names = [] + self.trees = obfuscateTool.parse_java_files(java_folder_path) + self.Literals = self.__extract_string_literals(self.trees) # [package,class,[Literals,,]] 이렇게 넣을 예정 + + + # trees 에서 각 tree 의 문자열들을 추출하고 Literals 에 package_class 와 함께 저장 + def __extract_string_literals(self, trees): + Literals = [] + string_literals = [] + package_name = None + class_name = None + for file_path, tree, source_code in trees: + for path, node in tree: + if isinstance(node, javalang.tree.PackageDeclaration): + package_name = node.name + + if isinstance(node, javalang.tree.ClassDeclaration): # 근데 클래스 밖에있는 문자열, 다른클래스에서 특정 클래스의 문자열을 불러온다면? + string_literals = [] + class_name = node.name + self.class_names.append([package_name,class_name]) + for sub_path,sub_node in node: + if isinstance(sub_node, javalang.tree.Literal) and isinstance(sub_node.value, str) and sub_node.value.startswith('"') and sub_node.value.endswith('"'): + #literal = sub_node.value[1:-1] + string_literals.append((sub_node.value, sub_node.position)) + Literals.append([package_name,class_name,string_literals]) # 클래스 별로 문자열 추출 + return Literals \ No newline at end of file diff --git a/src/main/resources/pyscripts/taintAnalysis.py b/src/main/resources/pyscripts/taintAnalysis.py index b0812539..dc8f877e 100644 --- a/src/main/resources/pyscripts/taintAnalysis.py +++ b/src/main/resources/pyscripts/taintAnalysis.py @@ -9,6 +9,7 @@ class taintAnalysis: __flow = [] flows = defaultdict(list) + #메서드 단위로 AST 노드 저장, Taint 변수 탐색 및 저장 def __init__(self, java_folder_path): # Step 1: Parse all Java files