def encodeShellcode(base_address, shellcode): base_address_parsed = re.match(REG % '|'.join(NOP.keys()), base_address, re.IGNORECASE) if base_address_parsed is None: raise Exception("Cannot parse \"%s\"." % base_address) base_address_register = base_address_parsed.group("R") nop = NOP[base_address_register.lower()]; base_address_offset = ALPHA3.toInt(base_address_parsed.group("I")) nopslide_size = ALPHA3.toInt(base_address_parsed.group("V")) patcher = ALPHA3.io.ReadFile("[%s+i32] - EDX.bin" % base_address_register, LOCAL_PATH) patch_offset = nopslide_size + len(patcher) ALPHA3.PrintVerboseStatusLine("Return address", "%s+%X" % (base_address_register, base_address_offset)) ALPHA3.PrintVerboseStatusLine("Nopslide size", "%X" % (nopslide_size,)) ALPHA3.PrintVerboseStatusLine("Patcher size", "%X" % (len(patcher),)) ALPHA3.PrintVerboseStatusLine("Countslide size", "%X" % (nopslide_size,)) ALPHA3.PrintVerboseStatusLine("Patch address", "%s+%X+%X" % (base_address_register, base_address_offset, patch_offset)) base_address_offset_encoded = ALPHA3.encode.dwx_IMUL_30_XOR_dwy( base_address_offset, "encoded base address offset", ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) patch_offset_encoded = ALPHA3.encode.dwx_IMUL_30_XOR_dwy( patch_offset, "encoded patch offset",ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) patcher = ALPHA3.encode.injectCodes(patcher, base_address_offset_encoded + patch_offset_encoded) countslide = (nop * nopslide_size + patcher + COUNT * nopslide_size) return countslide + ALPHA3.x86.ascii.mixedcase.rm32.encodeShellcode("edx", shellcode);
def RunEncoderTest(encoder_settings, base_address, test_args, int3): for i in range(len(test_args)): test_args[i] = test_args[i].replace("%shellcode%", "con") if (encoder_settings["architecture"] == "x86"): shellcode_file = TEST_X86_SHELLCODE_FILE shellcode = TEST_X86_SHELLCODE test_command = TEST_X86 elif (encoder_settings["architecture"] == "x64"): shellcode_file = TEST_X64_SHELLCODE_FILE shellcode = TEST_X64_SHELLCODE test_command = TEST_X64 else: ALPHA3.PrintVerboseStatusLine("Problem", "Encoder uses untestable architecture.") return ["[%s] Has an untestable architecture \"%s\"" % (encoder_settings["name"], architecture)] # Encode shellcode if "function args" in encoder_settings: encoder_function_args = encoder_settings["function args"]; else: encoder_function_args = {}; encoded_shellcode = encoder_settings["function"](base_address, shellcode, *encoder_function_args) encoding_errors = CheckEncodedShellcode(encoded_shellcode, encoder_settings) if encoding_errors: ALPHA3.PrintVerboseStatusLine("Problem", "Encoder failed to encode correctly.") return ["[%s] created encoded shellcode with bad characters for base address \"%s\":" % ( encoder_settings["name"], base_address)] + encoding_errors # Create test command line: if int3 and "--int3" not in test_args: test_args += ["--int3"] test_args += ["--EH"] command = "\"%s\" %s" % (test_command, " ".join(test_args)) # Output encoder and test command lines: ALPHA3.PrintVerboseStatusLine("Encode command", "ALPHA3.py %s %s %s %s --input=\"%s\"" % ( encoder_settings["architecture"], encoder_settings["character encoding"], encoder_settings["case"], base_address, ALPHA3.io.ShortPath(shellcode_file))) ALPHA3.PrintVerboseStatusLine("Test command", "\"%s\" %s" % ( ALPHA3.io.ShortPath(test_command), " ".join(test_args))) # Print test command line: try: popen = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) except WindowsError, e: if e.winerror == 193: # not a valid Win32 application ALPHA3.PrintVerboseStatusLine("Problem", "Encoder cannot be tested on your platform (ignored).") return None raise
def encodeShellcode(base_address, shellcode): base_address = ALPHA3.toInt(base_address) encoded_base_address = ALPHA3.encode.dwx_IMUL_by(base_address, "encoded base address", ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) if encoded_base_address is not None: decoder = ALPHA3.io.ReadFile("dwx_IMUL_by.bin", LOCAL_PATH) else: encoded_base_address = ALPHA3.encode.dwx_IMUL_30_XOR_dwy(base_address, "encoded base address", ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) decoder = ALPHA3.io.ReadFile("dwx_IMUL_30_XOR_dwy.bin", LOCAL_PATH) decoder = ALPHA3.encode.injectCodes(decoder, encoded_base_address) return ALPHA3.encode.encodeData(decoder, shellcode, ALPHA3.encode.bx_IMUL_30_XOR_by, # Use this encoding function ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) # And these characters to encode
def dwx_IMUL_30_XOR_dwy(value, status, valid_values): dwx, carry = makeValid(0, 4, valid_values) dwy, carry = makeValid(0, 4, valid_values) for byte in range(0, 4): byte_mask = 0xFF << (byte * 8) while 1: dwx_IMUL_30_XOR_dwy = ((dwx * 0x30) ^ dwy) & 0xFFFFFFFF ALPHA3.PrintVerboseStatus( status, "%08X * 30 ^ %08X == %08X" % (dwx, dwy, dwx_IMUL_30_XOR_dwy)) if (dwx_IMUL_30_XOR_dwy & byte_mask) == (value & byte_mask): break # OK: next byte x_byte = (dwx & byte_mask) >> (byte * 8) next_x_byte, carry = makeValid(x_byte + 1, 1, valid_values) dwx = (dwx & (0xFFFFFFFF ^ byte_mask)) ^ (next_x_byte << (byte * 8)) if carry: y_byte = (dwy & byte_mask) >> (byte * 8) next_y_byte, carry = makeValid(y_byte + 1, 1, valid_values) dwy = (dwy & (0xFFFFFFFF ^ byte_mask)) ^ (next_y_byte << (byte * 8)) assert carry == 0, "Cannot encode value!" # Should never happen! ALPHA3.PrintVerboseStatus() return [dwx, dwy]
def TestEncoder(encoder_settings, base_address, int3): assert "tests" in encoder_settings and encoder_settings["tests"], ( "No tests found in [%s] encoder." % (encoder_settings["name"])) problems = [] test_count = 0 error_count = 0 for test_base_address, test_args in encoder_settings["tests"].items(): if base_address is None or test_base_address.lower( ) == base_address.lower(): if test_count == 0: ALPHA3.PrintVerboseSeparator() base_address_test_found = True else: ALPHA3.PrintVerboseLine() if ALPHA3.g_output_verbosity_level == 0: ALPHA3.PrintStatus("[%s]" % encoder_settings["name"], "Test %d" % test_count) ALPHA3.PrintVerboseCenteredLine( "Testing encoder [%s] with base address \"%s\"" % (encoder_settings["name"], test_base_address)) # Run test test_count += 1 test_errors = RunEncoderTest(encoder_settings, test_base_address, test_args, int3) if test_errors: error_count += 1 problems += test_errors if test_count == 0: if base_address is None: # No filter, there are no tests! problems += [ "Encoder [%s] has no tests." % encoder_settings["name"] ] else: ALPHA3.PrintVerboseLine() # Create a result message: if error_count: passed_tests_message = "%d/%d tests." % (test_count - error_count, test_count) else: passed_tests_message = "all %d tests." % (test_count) if ALPHA3.g_output_verbosity_level == 0: ALPHA3.PrintStatusLine("[%s]" % encoder_settings["name"], "Passed %s" % passed_tests_message) else: ALPHA3.PrintVerboseCenteredLine( "Encoder [%s] passed %s" % (encoder_settings["name"], passed_tests_message)) return problems
def encodeShellcode(base_address, shellcode): base_address = ALPHA3.toInt(base_address) encoded_base_address = ALPHA3.encode.dwx_IMUL_by( base_address, "encoded base address", ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) if encoded_base_address is not None: decoder = ALPHA3.io.ReadFile("dwx_IMUL_by.bin", LOCAL_PATH) else: encoded_base_address = ALPHA3.encode.dwx_IMUL_30_XOR_dwy( base_address, "encoded base address", ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) decoder = ALPHA3.io.ReadFile("dwx_IMUL_30_XOR_dwy.bin", LOCAL_PATH) decoder = ALPHA3.encode.injectCodes(decoder, encoded_base_address) return ALPHA3.encode.encodeData( decoder, shellcode, ALPHA3.encode.bx_IMUL_30_XOR_by, # Use this encoding function ALPHA3.charsets.valid_charcodes["ascii"] ["mixedcase"]) # And these characters to encode
def encodeShellcode(base_address, shellcode): base_address = re.match(REG, base_address, re.IGNORECASE) nopslide_size = ALPHA3.toInt(base_address.group("V")) base_address = ALPHA3.toInt(base_address.group("I")) patcher = ALPHA3.io.ReadFile("[i32] - ECX.bin", LOCAL_PATH) patch_address = base_address + nopslide_size + len(patcher) ALPHA3.PrintVerboseStatusLine("return address", "%08X" % base_address) ALPHA3.PrintVerboseStatusLine("nopslide size", "%X" % nopslide_size) ALPHA3.PrintVerboseStatusLine("patcher size", "%X" % len(patcher)) ALPHA3.PrintVerboseStatusLine("countslide size", "%X" % nopslide_size) ALPHA3.PrintVerboseStatusLine("patch address", "%08X" % patch_address) patch_address_encoded = ALPHA3.encode.dwx_IMUL_30_XOR_dwy( patch_address, "encoded patch address", ALPHA3.charsets.valid_charcodes["ascii"]["mixedcase"]) patcher = ALPHA3.encode.injectCodes(patcher, patch_address_encoded) countslide = (NOP * nopslide_size + patcher + COUNT * nopslide_size) return countslide + ALPHA3.x86.ascii.mixedcase.rm32.encodeShellcode( "ecx", shellcode)
ALPHA3.PrintVerboseStatusLine("Encode command", "ALPHA3.py %s %s %s %s --input=\"%s\"" % ( encoder_settings["architecture"], encoder_settings["character encoding"], encoder_settings["case"], base_address, ALPHA3.io.ShortPath(shellcode_file))) ALPHA3.PrintVerboseStatusLine("Test command", "\"%s\" %s" % ( ALPHA3.io.ShortPath(test_command), " ".join(test_args))) # Print test command line: try: popen = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) except WindowsError, e: if e.winerror == 193: # not a valid Win32 application ALPHA3.PrintVerboseStatusLine("Problem", "Encoder cannot be tested on your platform (ignored).") return None raise stdout_data, stderr_data = popen.communicate(encoded_shellcode) if (stdout_data == TEST_SHELLCODE_OUTPUT and stderr_data == ""): ALPHA3.PrintVerboseStatusLine("Result", "Success") return None ALPHA3.PrintVerboseStatusLine("Result", "Failed") return ["[%s] failed test for base address \"%s\"" % (encoder_settings["name"], base_address), " stdout: %s" % repr(stdout_data), " stderr: %s" % repr(stderr_data)] def CheckEncodedShellcode(encoded_shellcode, encoder_settings): valid_chars = ALPHA3.charsets.valid_chars[encoder_settings["character encoding"]][encoder_settings["case"]] errors = [] index = 0 for char in encoded_shellcode: if char not in valid_chars: charcode_str = ALPHA3.charsets.charcode_fmtstr[encoder_settings["character encoding"]] % ord(char) errors += [" Byte %d @0x%02X: %s (%s)" % (index, index, char, charcode_str)] index += 1
def parent_path(path, parents): while parents > 0: parents -= 1 path = os.path.split(path)[0] return path sys.path.append(parent_path(__file__, 5)) import ALPHA3 def XX_IMUL_30_XOR_YY_XOR_XX(result, valid_values): # Find a way to encode a byte for XX in valid_values: XX_IMUL_30 = (XX * 0x30) & 0xFF for YY in valid_values: XX_IMUL_30_XOR_YY_XOR_XX = XX_IMUL_30 ^ YY ^ XX if XX_IMUL_30_XOR_YY_XOR_XX == result: return XX, YY raise AssertionError("Cannot encode %02X" % (result,)) def PrintValues(i): XX, YY = XX_IMUL_30_XOR_YY_XOR_XX(i, ALPHA3.ascii.mixedcase.VALUES) print "%02X %02X: %02X * 30 ^ %02X ^ %02X == %02X" % (XX, YY, XX, YY, XX, i) if __name__ == "__main__": if len(sys.argv) == 2: i = ALPHA3.toInt(sys.argv[1]) PrintValues(i) else: for i in range(0xFF): PrintValues(i)
sys.path.append(parent_path(__file__, 5)) import ALPHA3 def XX_IMUL_30_XOR_YY_XOR_XX(result, valid_values): # Find a way to encode a byte for XX in valid_values: XX_IMUL_30 = (XX * 0x30) & 0xFF for YY in valid_values: XX_IMUL_30_XOR_YY_XOR_XX = XX_IMUL_30 ^ YY ^ XX if XX_IMUL_30_XOR_YY_XOR_XX == result: return XX, YY raise AssertionError("Cannot encode %02X" % (result, )) def PrintValues(i): XX, YY = XX_IMUL_30_XOR_YY_XOR_XX(i, ALPHA3.ascii.mixedcase.VALUES) print "%02X %02X: %02X * 30 ^ %02X ^ %02X == %02X" % (XX, YY, XX, YY, XX, i) if __name__ == "__main__": if len(sys.argv) == 2: i = ALPHA3.toInt(sys.argv[1]) PrintValues(i) else: for i in range(0xFF): PrintValues(i)