/// <summary> /// Tests both the distorm_decompose and distorm_format functions. /// </summary> /// <returns>Returns true if both tests passed.</returns> public static bool DecomposeFormatTest() { string expectedOutput = "push ebp\n" + "mov ebp, esp\n" + "mov eax, [ebp+0x8]\n" + "add eax, [ebp+0xc]\n" + "leave\n" + "ret\n"; string actualOutput = string.Empty; GCHandle gch = GCHandle.Alloc(Program.code, GCHandleType.Pinned); // Prepare the _CodeInfo structure for decomposition. Distorm.CodeInfo ci = new Distorm.CodeInfo(); ci.codeLen = Program.code.Length; ci.code = gch.AddrOfPinnedObject(); ci.codeOffset = 0; ci.dt = Distorm.DecodeType.Decode32Bits; ci.features = Distorm.DecomposeFeatures.NONE; // Prepare the result instruction buffer to receive the decomposition. Distorm.DInst[] result = new Distorm.DInst[Program.code.Length]; uint usedInstructionsCount = 0; // Perform the decomposition. Distorm.DecodeResult r = Distorm.distorm_decompose(ref ci, result, (uint)result.Length, ref usedInstructionsCount); // Release the handle pinned to the code. gch.Free(); // Return false if an error occured during decomposition. if (!r.Equals(Distorm.DecodeResult.SUCCESS)) { return false; } // Prepare a _DecodedInst structure for formatting the results. Distorm.DecodedInst inst = new Distorm.DecodedInst(); for (uint i = 0; i < usedInstructionsCount; ++i) { // Format the results of the decomposition. Distorm.distorm_format(ref ci, ref result[i], ref inst); // Add it to the buffer to be verified. if (string.IsNullOrEmpty(inst.Operands)) { actualOutput += inst.Mnemonic + "\n"; } else { actualOutput += inst.Mnemonic + " " + inst.Operands + "\n"; } } return expectedOutput.Equals(actualOutput); }
public static bool DecomposeFormatTest2() { string actualOutput = string.Empty; GCHandle gch = GCHandle.Alloc(Program.code2, GCHandleType.Pinned); // Prepare the _CodeInfo structure for decomposition. Distorm.CodeInfo ci = new Distorm.CodeInfo(); ci.codeLen = Program.code2.Length; ci.code = gch.AddrOfPinnedObject(); ci.codeOffset = 0xFFBAB9D0; ci.dt = Distorm.DecodeType.Decode64Bits; ci.features = Distorm.DecomposeFeatures.NONE; // Prepare the result instruction buffer to receive the decomposition. Distorm.DInst[] result = new Distorm.DInst[Program.code2.Length]; uint usedInstructionsCount = 0; // Perform the decomposition. Distorm.DecodeResult r = Distorm.distorm_decompose(ref ci, result, (uint)result.Length, ref usedInstructionsCount); // Release the handle pinned to the code. gch.Free(); // Return false if an error occured during decomposition. if (!r.Equals(Distorm.DecodeResult.SUCCESS)) { return false; } Array.Resize(ref result, (int)usedInstructionsCount); return VerifyDecomposition2(result); }
/// <summary> /// Translates opcodes into a list of strings, which each represent an instruction. /// </summary> /// <param name="code">The code to be disassembled.</param> /// <param name="offset">The offset at which the code starts in the image being disassembled.</param> /// <param name="bitDepth">The target architecture type of the code being disassembled.</param> /// <returns>Returns the disassembled instructions.</returns> public static List<string> Disassemble( byte[] code, ulong offset = 0, DecodeType bitDepth = DecodeType.Decode32Bits) { List<string> instructions = new List<string>(); GCHandle gch = GCHandle.Alloc(code, GCHandleType.Pinned); // Prepare the CodeInfo structure for decomposition. Distorm.CodeInfo ci = new Distorm.CodeInfo(); ci.codeLen = code.Length; ci.code = gch.AddrOfPinnedObject(); ci.codeOffset = offset; ci.dt = bitDepth; ci.features = Distorm.DecomposeFeatures.NONE; // Prepare the result instruction buffer to receive the decomposition. Distorm.DInst[] result = new Distorm.DInst[code.Length]; uint usedInstructionsCount = 0; // Perform the decomposition. Distorm.DecodeResult r = Distorm.distorm_decompose(ref ci, result, (uint)result.Length, ref usedInstructionsCount); // Release the handle pinned to the code. gch.Free(); // Return an empty list if an error occured during decomposition. if (!r.Equals(Distorm.DecodeResult.SUCCESS)) { return new List<string>(); } // Prepare a DecodedInst structure for formatting the results. Distorm.DecodedInst inst = new Distorm.DecodedInst(); for (uint i = 0; i < usedInstructionsCount; ++i) { // Format the results of the decomposition. Distorm.distorm_format(ref ci, ref result[i], ref inst); // Add it to the buffer to be verified. if (string.IsNullOrEmpty(inst.Operands)) { instructions.Add(inst.Mnemonic); } else { instructions.Add(inst.Mnemonic + " " + inst.Operands); } } return instructions; }
/// <summary> /// Tests the DistormSimple.distorm_decompose() function. /// </summary> /// <returns>Returns true if the test passed.</returns> public static bool DecomposeOnlyTest() { GCHandle gch = GCHandle.Alloc(Program.code, GCHandleType.Pinned); Distorm.CodeInfo ci = new Distorm.CodeInfo(); ci.codeLen = Program.code.Length; ci.code = gch.AddrOfPinnedObject(); ci.codeOffset = 0; ci.dt = Distorm.DecodeType.Decode32Bits; ci.features = Distorm.DecomposeFeatures.NONE; Distorm.DInst[] result = new Distorm.DInst[Program.code.Length]; uint usedInstructionsCount = 0; Distorm.DecodeResult r = Distorm.distorm_decompose(ref ci, result, (uint)result.Length, ref usedInstructionsCount); // Release the handle pinned to the code. gch.Free(); // Return false if an error occured during decomposition. if (!r.Equals(Distorm.DecodeResult.SUCCESS)) { return false; } if (usedInstructionsCount < 6) { return false; } // Manually check each instruction. if (result[0].InstructionType != Distorm.InstructionType.PUSH || result[0].ops[0].RegisterName != "ebp") { return false; } else if (result[1].InstructionType != Distorm.InstructionType.MOV || result[1].ops[0].RegisterName != "ebp" || result[1].ops[1].RegisterName != "esp") { return false; } else if (result[2].InstructionType != Distorm.InstructionType.MOV || result[2].ops[0].RegisterName != "eax" || result[2].ops[1].type != Distorm.OperandType.SMEM || result[2].ops[1].RegisterName != "ebp" || result[2].disp != 0x8) { return false; } else if (result[3].InstructionType != Distorm.InstructionType.ADD || result[3].ops[0].RegisterName != "eax" || result[3].ops[1].type != Distorm.OperandType.SMEM || result[3].ops[1].RegisterName != "ebp" || result[3].disp != 0xc) { return false; } else if (result[4].InstructionType != Distorm.InstructionType.LEAVE) { return false; } else if (result[5].InstructionType != Distorm.InstructionType.RET) { return false; } return true; }
/// <summary> /// A wrapper for distorm_decompose(), which only takes in the code to be decomposed. /// </summary> /// <param name="code">The code to be decomposed.</param> /// <param name="offset">The offset at which the code starts in the image being disassembled.</param> /// <param name="bitDepth">The target architecture type of the code being disassembled.</param> /// <param name="logFilename"> /// The name of the file to use to log important updates about the decomposition process. /// </param> /// <returns>Returns the code to be decomposed on success or an empty array upon failure.</returns> /// <remarks> /// Usage of brainpower is required to recognize that decomposing a code array of size 0 will also result in /// an empty array. /// </remarks> public static DInst[] Decompose( byte[] code, ulong offset = 0, DecodeType bitDepth = DecodeType.Decode32Bits, string logFilename = "Distorm3cs.log") { GCHandle gch = GCHandle.Alloc(code, GCHandleType.Pinned); Distorm.CodeInfo ci = new Distorm.CodeInfo(); ci.codeLen = code.Length; ci.code = gch.AddrOfPinnedObject(); ci.codeOffset = offset; ci.dt = bitDepth; ci.features = Distorm.DecomposeFeatures.NONE; // Most likely a gross over-estimation of how large to make the array, but it should never fail. Distorm.DInst[] result = new Distorm.DInst[code.Length]; uint usedInstructionsCount = 0; // Decompose the data. Distorm.DecodeResult r = Distorm.distorm_decompose(ref ci, result, (uint)result.Length, ref usedInstructionsCount); // Release the handle pinned to the code. gch.Free(); // Return false if an error occured during decomposition. if (!r.Equals(Distorm.DecodeResult.SUCCESS)) { Logger.Log( "Error decomposing data. Result was: " + r.ToString(), logFilename, Logger.Type.CONSOLE | Logger.Type.FILE); return new Distorm.DInst[0]; } // Resize the array to match the actual number of instructions decoded. Array.Resize(ref result, (int)usedInstructionsCount); // Return the result. return result; }