private ICode ExpandTargetAddressOfJumpInstructionTo4Bytes(ICode code, IInstructionWithAddressOperandDecider InstructionWithAddressOperandDecider, IInstructionWithAddressOperandTransform InstructionWithAddressOperandTransform, ICodeTransform codeTransform, IStatistics statistics) { TryTransformInstructionDelegate transformInstructionDelegate = (IAssemblyInstructionForTransformation instruction, IBasicBlock basicBlock, IFunction function, out List <IAssemblyInstructionForTransformation> listOfTransformedInstructions) => { listOfTransformedInstructions = null; var wasTransformed = false; //replace jump instruction to jump instructions with 4 bytes operand= if (InstructionWithAddressOperandDecider.IsJumpInstructionWithRelativeAddressOperand(instruction) && IsJumpInstructionToCodeSection(code, instruction)) { if (InstructionWithAddressOperandTransform.TryTransformJumpInstructionTo4BytesOperandSize(instruction, out IAssemblyInstructionForTransformation transformedInstruction)) { wasTransformed = true; listOfTransformedInstructions = new List <IAssemblyInstructionForTransformation>() { transformedInstruction }; statistics.IncrementInstructionExpanded((uint)(transformedInstruction.Bytes.Length - instruction.Bytes.Length)); } } return(wasTransformed); }; return(codeTransform.Transform(code, transformInstructionDelegate)); }
private ICode UpdateJumpInstructionsTargetAddress(ICode code, IInstructionWithAddressOperandDecider InstructionWithAddressOperandDecider, IInstructionWithAddressOperandTransform InstructionWithAddressOperandTransform, ICodeTransform codeTransform, Dictionary <ulong, IAssemblyInstructionForTransformation> addressToInstructionMap, ICodeInMemoryLayoutFactory codeInMemoryLayoutFactory, IRelocationDirectoryFromNewCode relocationDirectoryFromNewCode, Dictionary <ulong, ulong> jumpInstructionsMap) { if (code == null) { throw new ArgumentNullException(nameof(code)); } if (code.AssemblyInstructions == null || code.AssemblyInstructions.Count == 0) { throw new ArgumentException("code.AssemblyInstructions"); } if (InstructionWithAddressOperandDecider == null) { throw new ArgumentNullException(nameof(InstructionWithAddressOperandDecider)); } if (InstructionWithAddressOperandTransform == null) { throw new ArgumentNullException(nameof(InstructionWithAddressOperandTransform)); } if (codeInMemoryLayoutFactory == null) { throw new ArgumentNullException(nameof(codeInMemoryLayoutFactory)); } if (relocationDirectoryFromNewCode == null) { throw new ArgumentNullException(nameof(relocationDirectoryFromNewCode)); } //this is used map for the new and old addresses var oldToNewAddressDictionary = jumpInstructionsMap; //PASS 1: //map old instruction address to new address, //because new instructions are going to be added in between, and other instructions //are going to be expanded. ulong newOffset = 0; foreach (var instruction in code.AssemblyInstructions) { //look for each byte in instruction, because the addresses in operand //can be an instruction or somewhere INSIDE the instruction //for example: movzx eax, byte [edx+0x411d8c] //where edx = 0xbc, and 0x411d8c is no instruction for (ulong i = 0; i < (ulong)instruction.Bytes.Length; i++) { if (oldToNewAddressDictionary.ContainsKey(instruction.Offset + i)) { oldToNewAddressDictionary[instruction.Offset + i] = newOffset + i; } } newOffset = newOffset + (ulong)instruction.Bytes.Length; } //PASS 2:Create the new relocation directory var newRelocationDirectoryInfo = relocationDirectoryFromNewCode.CreateNewRelocationDirectoryInfo(code); //PASS 3: //set the target jump address to the new address and then change the instruction offset newOffset = 0; ulong newProgramCounter = 0; TryTransformInstructionDelegate tryTransformDelegate = (IAssemblyInstructionForTransformation instruction, IBasicBlock basicBlock, IFunction function, out List <IAssemblyInstructionForTransformation> transformedInstructions) => { transformedInstructions = null; var retVal = false; //old jump target address or old address in operand ulong oldAddress; newProgramCounter = newProgramCounter + (ulong)instruction.Bytes.Length; bool isJumpTargetOperand = InstructionWithAddressOperandDecider.IsJumpInstructionWithRelativeAddressOperand(instruction) || InstructionWithAddressOperandDecider.IsCallInstructionWithAddressOperand(instruction); bool isAbsoluteAddressInOperand = InstructionWithAddressOperandDecider.IsInstructionWithAbsoluteAddressOperand(instruction, code.CodeInMemoryLayout, out oldAddress); if (isJumpTargetOperand) { transformedInstructions = new List <IAssemblyInstructionForTransformation>(); oldAddress = instruction.GetAbsoluteAddressFromRelativeAddress(); if (!oldToNewAddressDictionary.TryGetValue(oldAddress, out ulong newTargetAddress)) { throw new ApplicationException("jump instruction target should exist on map"); } var transformedInstruction = InstructionWithAddressOperandTransform. CreateJumpInstructionWithNewTargetAddress(instruction, newProgramCounter, newOffset, newTargetAddress); transformedInstructions.Add(transformedInstruction); retVal = true; } else if (isAbsoluteAddressInOperand) { transformedInstructions = new List <IAssemblyInstructionForTransformation>(); ulong virtualOldAddress = (oldAddress - code.CodeInMemoryLayout.ImageBaseAddress) - code.CodeInMemoryLayout.CodeVirtualAddress; if (!oldToNewAddressDictionary.TryGetValue(virtualOldAddress, out ulong newAddressInOperand)) { throw new ApplicationException("jump instruction target should exist on map"); } newAddressInOperand += (code.CodeInMemoryLayout.ImageBaseAddress + code.CodeInMemoryLayout.CodeVirtualAddress); var transformedInstruction = InstructionWithAddressOperandTransform. CreateInstructionWithNewAddress(code, instruction, newProgramCounter, newOffset, oldAddress, newAddressInOperand); transformedInstructions.Add(transformedInstruction); retVal = true; } else { instruction.SetPC(newProgramCounter); instruction.SetOffset(newOffset); } newOffset = newProgramCounter; return(retVal); }; //take care for updating the new entry point address, and new relocation diretory //define a factory to create the new code in memory layout instance Func <ICodeInMemoryLayout> codeInMemoryLayoutFactoryDelegate = () => codeInMemoryLayoutFactory.Create( code.CodeInMemoryLayout.ImageBaseAddress, code.CodeInMemoryLayout.OffsetOfCodeInBytes, newProgramCounter, code.CodeInMemoryLayout.CodePhysicalSizeInBytes, oldToNewAddressDictionary[code.CodeInMemoryLayout.EntryPointOffset], code.CodeInMemoryLayout.CodeVirtualAddress, newRelocationDirectoryInfo); var newCode = codeTransform.Transform(code, tryTransformDelegate, codeInMemoryLayoutFactoryDelegate); return(newCode); }
protected override ICode TransformCode(ICode code, Dictionary <ulong, IAssemblyInstructionForTransformation> addressToInstructionMap, Dictionary <ulong, ulong> addressesInInstructionMap) { //inicate weather to try insert junk in the next instruction. //a junk will be inserted if the instruction right after is the first in basic block bool insertJunk = false; //define the delegate that transform a single instruction. //this delegate is passes to a code transformer that execute this delegate on each assembly instruction TryTransformInstructionDelegate transformInstructionDelegate = (IAssemblyInstructionForTransformation instruction, IBasicBlock basicBlock, IFunction function, out List <IAssemblyInstructionForTransformation> listOfTransformedInstructions) => { var wasTransformed = false; listOfTransformedInstructions = null; //insert junk only inside a basic block if (basicBlock == null) { //if the should insert junk is set, but next instructions are not nops turn off the junk //insertion flag, because there is no basic block to insert the junk into if (!instruction.IsNopInstruction()) { insertJunk = false; } return(wasTransformed); } //try insert junk instruction if (insertJunk) { if (TryGenerateJunkInstruction(basicBlock, m_junkBytesProvider, m_statistics, out IAssemblyInstructionForTransformation junkInstruction)) { m_statistics.IncrementAddedInstructions(1, (uint)junkInstruction.Bytes.Length); listOfTransformedInstructions = new List <IAssemblyInstructionForTransformation> { //insert junk insruction before the first instruction of the basic block junkInstruction, instruction }; insertJunk = false; wasTransformed = true; } //can not insert junk in the basic block. do not try to insert junk bytes else { insertJunk = false; return(wasTransformed); } } //The it is last instruction in basic block, and if it is unconditional if (basicBlock.AssemblyInstructions.Last() == instruction) { if (m_instructionWithAddressOperandDecider.IsUnconditionalJumpInstruction(instruction.Mnemonic) || m_instructionWithAddressOperandDecider.IsReturnInstruction(instruction)) { insertJunk = true; } } return(wasTransformed); }; return(m_codeTransform.Transform(code, transformInstructionDelegate)); }
public ICode Transform(ICode code, TryTransformInstructionDelegate transformInstructionDelegate, Func <ICodeInMemoryLayout> codeInLayoutFactoryDelegate = null) { var newInstructionsList = new List <IAssemblyInstructionForTransformation>(); var newFunctionsList = new List <IFunction>(); var instructionListIterator = code.AssemblyInstructions.GetEnumerator(); var lastInstructionInLastBlock = code.Functions.Last().BasicBlocks.Last().AssemblyInstructions.Last(); IAssemblyInstructionForTransformation previousInstruction = null; bool afterInstructionOfLastBlock = false; //move to the first instruction instructionListIterator.MoveNext(); //iterate through all functions foreach (var function in code.Functions) { var basicBlockList = new List <IBasicBlock>(); //iterate through all basic block foreach (var basicBlock in function.BasicBlocks) { var instructionsListOfBlock = new List <IAssemblyInstructionForTransformation>(); foreach (var instructionInBasicBlock in basicBlock.AssemblyInstructions) { bool isInstructionInBasicBlock; bool done = false; //transform instructions from instruction list. //this loop transform: //1. instructions before the basic block which are left to process //2. instructions inside a basic block //3. instructions after the last basic block while (!done) { isInstructionInBasicBlock = instructionListIterator.Current == instructionInBasicBlock; IAssemblyInstructionForTransformation instructionToTransform = instructionListIterator.Current; //perfom the transformation of the instruction List <IAssemblyInstructionForTransformation> transformedInstructionList; var wasTransformed = transformInstructionDelegate(instructionToTransform, isInstructionInBasicBlock ? basicBlock : null, isInstructionInBasicBlock ? function : null, out transformedInstructionList); if (wasTransformed) { if (transformedInstructionList.Count == 0) { throw new ApplicationException("transformation should return at least one instruction"); } if (isInstructionInBasicBlock) { instructionsListOfBlock.AddRange(transformedInstructionList); } newInstructionsList.AddRange(transformedInstructionList); if (previousInstruction != null) { transformedInstructionList[0].PreviousInstruction = previousInstruction; previousInstruction.NextInstruction = transformedInstructionList[0]; } if (transformedInstructionList.Count > 1) { for (int i = 1; i < transformedInstructionList.Count; i++) { transformedInstructionList[i].PreviousInstruction = transformedInstructionList[i - 1]; transformedInstructionList[i - 1].NextInstruction = transformedInstructionList[i]; } } previousInstruction = transformedInstructionList.Last(); } else { if (isInstructionInBasicBlock) { instructionsListOfBlock.Add(instructionToTransform); } newInstructionsList.Add(instructionToTransform); if (previousInstruction != null) { instructionToTransform.PreviousInstruction = previousInstruction; previousInstruction.NextInstruction = instructionToTransform; } previousInstruction = instructionToTransform; } //check weather this is the last instruction in the last basic block if (isInstructionInBasicBlock && !afterInstructionOfLastBlock) { //The transformed instruction is now in the end of program //after the last basic block instruction afterInstructionOfLastBlock = (instructionToTransform == lastInstructionInLastBlock); } instructionListIterator.MoveNext(); //stop transforming intructions in loop when all instruction in scope are processed done = (isInstructionInBasicBlock || instructionListIterator.Current == null); //keep transforming after the last basic block instruction to the end of the program if (afterInstructionOfLastBlock && instructionListIterator.Current != null) { done = false; } } } IBasicBlock newBasicBlock = m_basicBlockFactory.Create(instructionsListOfBlock); basicBlockList.Add(newBasicBlock); } var newFunction = m_functionFactory.Create(basicBlockList.First().AssemblyInstructions.First(), basicBlockList.Last().AssemblyInstructions.Last(), basicBlockList); newFunctionsList.Add(newFunction); } //if there is a factory to create a new code in memory layout structure than use it, otherwise use //the original code layout in memrory instance ICodeInMemoryLayout codeInMemoryLayout = codeInLayoutFactoryDelegate == null ? code.CodeInMemoryLayout:codeInLayoutFactoryDelegate(); //return m_codeFactory.Create(newInstructionsList, newFunctionsList,codeInMemoryLayout); var newcode = m_codeFactory.Create(newInstructionsList, newFunctionsList, codeInMemoryLayout); ValidateNewCode(newcode); return(newcode); }
protected override ICode TransformCode(ICode code, Dictionary <ulong, IAssemblyInstructionForTransformation> addressToInstructionMap, Dictionary <ulong, ulong> addressesInInstructionMap) { //define the delegate that transform a single instruction. //this delegate is passes to a code transformer that execute this delegate on each assembly instruction TryTransformInstructionDelegate transformInstructionDelegate = (IAssemblyInstructionForTransformation instruction, IBasicBlock basicBlock, IFunction function, out List <IAssemblyInstructionForTransformation> listOfTransformedInstructions) => { listOfTransformedInstructions = null; //change unconditional jumps only inside a basic block if (basicBlock == null) { return(false); } //transformation made only on conditional jump intructions if (!m_instructionWithAddressOperandDecider.IsConditionalJumpInstruction(instruction.Mnemonic)) { return(false); } //because the new inserted jump instruction target address is the instruction after if (instruction.NextInstruction == null) { return(false); } //transform an unconditional jump instruction. //jump by condition C to address A //instruction after //=> // jump by inverse condition to address of instruction after //Jump to address A //instruction after //for example // instruction address instruction operands // 000017ba ja 0x17e7 // 000017c0 mov ecx, [eax * 4 + 0x41a00c] // is tranformed into // 000017ba jbe 000017c5 // 000017c0 jmp 0x17e7 // 000017c5 mov ecx, [eax * 4 + 0x41a00c] //IGenericTransform.UpdateJumpInstructionsTargetAddress updates the target address //of all instructions to the new one so, this transformation create those instructions // instruction address instruction operands // 000017ba jbe 000017c0 (will be updated to 000017c5) // 000017ba jmp 0x17e7 (will updated to 0x17e7 +5) // 000017c0 mov ecx, [eax * 4 + 0x41a00c] //create a new negative jump to the next instruction IAssemblyInstructionForTransformation newConditionalJumpInstruction; if (!m_instructionWithAddressOperandTransform.TryCreateNegativeJumpIntruction( instruction, 0, out newConditionalJumpInstruction)) { return(false); } newConditionalJumpInstruction.SetOffset(instruction.Offset); newConditionalJumpInstruction.SetPC(instruction.PC); //create a new jump instruction to the same address as the original condition jump condition var jumpAddress = instruction.GetRelativeAddress(); var newJumpInstruction = m_instructionWithAddressOperandTransform. CreateUnconditionalJumpInstruction(jumpAddress); newJumpInstruction.IsNew = true; newJumpInstruction.SetPC(instruction.PC); newJumpInstruction.SetOffset(instruction.Offset); listOfTransformedInstructions = new List <IAssemblyInstructionForTransformation>() { newConditionalJumpInstruction, newJumpInstruction }; //update dictionary of target addresses that apears in program. //this addresses have to be replaced later in the instructions that contain them (as operand). addressesInInstructionMap[instruction.NextInstruction.Offset] = 0; var addedBytesForConditionalJump = instruction.Bytes.Length - newConditionalJumpInstruction.Bytes.Length; m_statistics.IncrementAddedInstructions(1, (uint)(newJumpInstruction.Bytes.Length + addedBytesForConditionalJump)); return(true); }; var newCode = m_codeTransform.Transform(code, transformInstructionDelegate); //after this transformation there are more basic blocks, so parse them again return(m_codeParser.ParseCode(newCode.AssemblyInstructions, newCode.CodeInMemoryLayout)); }