SHOW:
|
|
- or go back to the newest paste.
| 1 | def decode_atomiku(self, file_name): | |
| 2 | """ | |
| 3 | De-obfuscates code that has been encoded with http://atomiku.com/online-php-code-obfuscator/ | |
| 4 | :param file_name: File to be decoded | |
| 5 | :return: Returns the de-obfuscated code or None if failed to decode | |
| 6 | """ | |
| 7 | ||
| 8 | # Open up the file for reading | |
| 9 | with open(file_name, 'r') as file_handle: | |
| 10 | file_data = file_handle.read() | |
| 11 | ||
| 12 | # Regex patterns for different recursive layers | |
| 13 | search_code_1 = (r'preg_replace\(\"\/\.\*\/e\",\s*\"\\x65\\x76\\x61\\x6C\\x28\\x67\\x7A\\x69\\x6E\\x66\\x6C' | |
| 14 | r'\\x61\\x74\\x65\\x28\\x62\\x61\\x73\\x65\\x36\\x34\\x5F\\x64\\x65\\x63\\x6F\\x64\\x65' | |
| 15 | r'\\x28\'(?P<encoded_code>.+)\'\\x29\\x29\\x29\\x3B\",\s*\"\"\);(?!preg_replace)') | |
| 16 | search_code_2 = (r'preg_replace\(\"\/\.\*\/e\",\s*\"\\x65\\x76\\x61\\x6C\\x28\\x67\\x7A\\x69\\x6E\\x66\\x6C' | |
| 17 | r'\\x61\\x74\\x65\\x28\\x62\\x61\\x73\\x65\\x36\\x34\\x5F\\x64\\x65\\x63\\x6F\\x64\\x65' | |
| 18 | r'\\x28\'(?P<encoded_code_1>.+)\'\\x29\\x29\\x29\\x3B\",\s*\"\"\);preg_replace' | |
| 19 | r'\(\"\/\.\*\/e\",\s*\"\\x65\\x76\\x61\\x6C\\x28\\x67\\x7A\\x69\\x6E\\x66\\x6C\\x61\\x74' | |
| 20 | r'\\x65\\x28\\x62\\x61\\x73\\x65\\x36\\x34\\x5F\\x64\\x65\\x63\\x6F\\x64\\x65\\x28\'' | |
| 21 | r'(?P<encoded_code_2>.+)\'\\x29\\x29\\x29\\x3B\",\s*\"\"\);') | |
| 22 | search_code_3 = (r'\$[\w\d]+\s*.=\s*\"(?P<encoded_1>.+)\";\s*\$[\w\d]+\s*.=\s*\"(?P<encoded_2>.+)\";\s*\$' | |
| 23 | r'[\w\d]+\s*.=\s*\"(?P<encoded_3>.+)\";\s*\$[\w\d]+\s*.=\s*\"(?P<encoded_4>.+)\";') | |
| 24 | search_code_4 = r'eval\([\w\d]+\(\"(?P<encoded_code>.+)\"\)\);' | |
| 25 | ||
| 26 | first_run = True | |
| 27 | still_matches = True | |
| 28 | obfuscated_code = None | |
| 29 | ||
| 30 | while still_matches: | |
| 31 | if first_run: | |
| 32 | first_run = False | |
| 33 | ||
| 34 | # First round will always follow the same pattern | |
| 35 | regex = re.compile(search_code_1) | |
| 36 | match = regex.search(file_data) | |
| 37 | ||
| 38 | if match: | |
| 39 | # De-obfuscate the layer and continue to next round | |
| 40 | obfuscated_code = self.gzinflate(self.base64_decode(match.group('encoded_code')))
| |
| 41 | continue | |
| 42 | else: | |
| 43 | # If no match, likely a corrupted file. Return None | |
| 44 | return None | |
| 45 | else: | |
| 46 | # On subsequent runs | |
| 47 | ||
| 48 | if obfuscated_code is None: # If this is None, likely a corrupted file. | |
| 49 | return None | |
| 50 | ||
| 51 | # First check for double preg_replace() pattern | |
| 52 | regex = re.compile(search_code_2) | |
| 53 | match = regex.search(obfuscated_code) | |
| 54 | ||
| 55 | if match: | |
| 56 | # De-obfuscate the layer and continue to next round | |
| 57 | # We only need the code from the second preg_replace() | |
| 58 | obfuscated_code = self.base64_decode(match.group('encoded_code_2'))
| |
| 59 | obfuscated_code = self.gzinflate(obfuscated_code) | |
| 60 | continue | |
| 61 | ||
| 62 | # Check for single preg_replace() pattern | |
| 63 | regex = re.compile(search_code_1) | |
| 64 | match = regex.search(obfuscated_code) | |
| 65 | ||
| 66 | if match: | |
| 67 | # De-obfuscate the layer and continue to next round | |
| 68 | obfuscated_code = self.base64_decode(match.group('encoded_code'))
| |
| 69 | obfuscated_code = self.gzinflate(obfuscated_code) | |
| 70 | continue | |
| 71 | ||
| 72 | # Check for 4 randomly named variables pattern | |
| 73 | regex = re.compile(search_code_3) | |
| 74 | match = regex.search(obfuscated_code) | |
| 75 | ||
| 76 | if match: | |
| 77 | # Append all for variables together and convert hex to ascii and move to next round | |
| 78 | obfuscated_code = match.group('encoded_1') + match.group('encoded_2') + \
| |
| 79 | match.group('encoded_3') + match.group('encoded_4')
| |
| 80 | obfuscated_code = obfuscated_code.replace('\\x', '').decode('hex')
| |
| 81 | continue | |
| 82 | ||
| 83 | # Check for final eval() pattern | |
| 84 | regex = re.compile(search_code_4) | |
| 85 | match = regex.search(obfuscated_code) | |
| 86 | ||
| 87 | if match: | |
| 88 | # De-obfuscate and go through one more round in case of more rounds | |
| 89 | obfuscated_code = self.gzinflate(self.base64_decode(match.group('encoded_code')))
| |
| 90 | continue | |
| 91 | ||
| 92 | # No more matches, end while loop | |
| 93 | still_matches = False | |
| 94 | ||
| 95 | # Return de-obfuscated code, trim ?> from beginning of string | |
| 96 | return obfuscated_code[2:] |