private static void MergePath(CodePath targetPath, CodePath newPath) { HLInstruction hlInstruction = newPath.StartInstruction; if (targetPath.EndInstruction == null) { targetPath.StartInstruction = hlInstruction; hlInstruction.PreviousInstruction = null; } else { targetPath.EndInstruction.NextInstruction = hlInstruction; hlInstruction.PreviousInstruction = targetPath.EndInstruction; } while (true) { newPath.InstructionMap.Remove(hlInstruction.Instruction.Offset); hlInstruction.ParentCodePath = targetPath; targetPath.InstructionMap.Add(hlInstruction.Instruction.Offset, hlInstruction); if (hlInstruction.NextInstruction == null) { break; } hlInstruction = hlInstruction.NextInstruction; } targetPath.EndInstruction = hlInstruction; targetPath.EndOffset = hlInstruction.Instruction.Offset + hlInstruction.Instruction.InstructionLength; newPath.ParentFunction.CodePaths.Remove(newPath); }
private void AnalyzeConditionalBranch(HLInstruction branchInstruction) { int branchOffset = branchInstruction.Instruction.Offset + branchInstruction.Instruction.InstructionLength; CodePath parentPath = branchInstruction.ParentCodePath; CodePath branchCodePath = CreateCodePath("if", branchOffset, parentPath); branchCodePath.ParentExitInstruction = branchInstruction; bool condition = branchInstruction.Instruction.OpCode == OpCode.JumpFalse ? true : false; branchInstruction.BranchCodesPaths.Add(condition, branchCodePath); branchInstruction.DefaultConditional = condition; AnalyzeCodePath(branchCodePath); if (branchInstruction.NextInstruction != null && branchCodePath.ParentEntryTargetInstruction != branchInstruction.NextInstruction) { // Well, shit.. we got an else block. CodePath branchElseCodePath = ExtractPath("if_else", branchInstruction.ParentCodePath, branchInstruction, branchInstruction.NextInstruction, branchCodePath.ParentEntryInstruction); branchInstruction.BranchCodesPaths.Add(!condition, branchElseCodePath); } }
private static CodePath CreateCodePath(string identifier, int startOffset, CodePath parentPath) { CodePath path = parentPath.ParentFunction.CreateCodePath(string.Format("{0}_{1:x}", identifier, startOffset)); path.ParentCodePath = parentPath; path.StartOffset = startOffset; return(path); }
public CodePath CreateCodePath(string name) { var path = new CodePath(); path.Name = name; path.ParentFunction = this; CodePaths.Add(path); return path; }
public CodePath CreateCodePath(string name) { var path = new CodePath(); path.Name = name; path.ParentFunction = this; CodePaths.Add(path); return(path); }
private void AnalyzeSwitchBranch(HLInstruction branchInstruction) { var sw = branchInstruction.Instruction as InstructionSwitch; CodePath parentPath = branchInstruction.ParentCodePath; var swMap = new Dictionary <int, CodePath>(); bool allWereReturns = true; HLInstruction switchExitInstruction = branchInstruction.NextInstruction.NextInstruction; foreach (var item in sw.SwitchTable) { if (swMap.ContainsKey(item.Value)) { // Deal with multiple values leading to the same code path branchInstruction.BranchCodesPaths.Add(item.Key, swMap[item.Value]); } else { CodePath branchCodePath = CreateCodePath("sw_case_" + item.Key, item.Value, parentPath); branchCodePath.ParentExitInstruction = branchInstruction; branchInstruction.BranchCodesPaths.Add(item.Key, branchCodePath); swMap.Add(item.Value, branchCodePath); AnalyzeCodePath(branchCodePath); if (branchCodePath.ParentEntryInstruction != null) { allWereReturns = false; switchExitInstruction = branchCodePath.ParentEntryInstruction; } } } if (allWereReturns) { switchExitInstruction = null; } if (switchExitInstruction != branchInstruction.NextInstruction.NextInstruction) { // Crappy... got a default case statement that we need to extract CodePath branchDefaultCodePath = ExtractPath("sw_case_default", parentPath, branchInstruction, branchInstruction.NextInstruction, switchExitInstruction); branchInstruction.BranchCodesPaths.Add(new object(), branchDefaultCodePath); } }
/// <summary> /// Dumps a codepath to debug /// </summary> /// <param name="path"></param> private static void DumpCodePath(CodePath path) { HLInstruction instruction = path.StartInstruction; while (instruction != null) { Debug.WriteLine(instruction.Instruction.ToString()); if (instruction.BranchCodesPaths != null && instruction.BranchCodesPaths.Count > 0) { foreach (var item in instruction.BranchCodesPaths) { Debug.WriteLine(" " + item.Key + " --> " + item.Value.Name); } } instruction = instruction.NextInstruction; } }
private static CodePath FindCommonPathAncestor(CodePath path1, CodePath path2) { var paths = new Dictionary <CodePath, object>(); while (path1 != null) { paths.Add(path1, null); path1 = path1.ParentCodePath; } while (path2 != null) { if (paths.ContainsKey(path2)) { return(path2); } path2 = path2.ParentCodePath; } return(null); }
private static CodePath FindCommonPathAncestor(CodePath path1, CodePath path2) { var paths = new Dictionary<CodePath, object>(); while(path1 != null) { paths.Add(path1, null); path1 = path1.ParentCodePath; } while(path2 != null) { if (paths.ContainsKey(path2)) { return path2; } path2 = path2.ParentCodePath; } return null; }
/// <summary> /// Extracts a sequence of instructions into a new sub codepath /// </summary> /// <param name="identifier"></param> /// <param name="parentPath"></param> /// <param name="parentExitInstruction"></param> /// <param name="startInstruction">inclusive</param> /// <param name="endInstruction">exclusive (this is where our codepath returns to)</param> /// <returns></returns> private static CodePath ExtractPath(string identifier, CodePath parentPath, HLInstruction parentExitInstruction, HLInstruction startInstruction, HLInstruction endInstruction) { CodePath toPath = CreateCodePath(identifier, startInstruction.Instruction.Offset, parentPath); toPath.ParentCodePath = parentPath; toPath.ParentExitInstruction = parentExitInstruction; HLInstruction hlInstruction = startInstruction; while (true) { parentPath.InstructionMap.Remove(hlInstruction.Instruction.Offset); hlInstruction.ParentCodePath = toPath; toPath.InstructionMap.Add(hlInstruction.Instruction.Offset, hlInstruction); if (hlInstruction.NextInstruction == null || hlInstruction.NextInstruction == endInstruction) { hlInstruction.NextInstruction = null; break; } hlInstruction = hlInstruction.NextInstruction; } if (startInstruction.PreviousInstruction != null) { startInstruction.PreviousInstruction.NextInstruction = endInstruction; } else { parentPath.StartInstruction = endInstruction; if (endInstruction != null) { parentPath.StartOffset = endInstruction.Instruction.Offset; } } if (endInstruction != null) { endInstruction.PreviousInstruction = startInstruction.PreviousInstruction; } if (endInstruction == null) { parentPath.EndInstruction = startInstruction.PreviousInstruction; if (parentPath.EndInstruction != null) { parentPath.EndOffset = parentPath.EndInstruction.Instruction.Offset + parentPath.EndInstruction.Instruction.InstructionLength; } else { parentPath.EndOffset = parentPath.StartOffset; } } startInstruction.PreviousInstruction = null; toPath.StartInstruction = startInstruction; toPath.EndInstruction = hlInstruction; toPath.EndOffset = hlInstruction.Instruction.Offset + hlInstruction.Instruction.InstructionLength; if (endInstruction != null && parentPath == endInstruction.ParentCodePath) { toPath.ParentEntryInstruction = endInstruction; } else { toPath.ParentEntryInstruction = null; } return(toPath); }
/// <summary> /// Extracts a sequence of instructions into a new sub codepath /// </summary> /// <param name="identifier"></param> /// <param name="parentPath"></param> /// <param name="parentExitInstruction"></param> /// <param name="startInstruction">inclusive</param> /// <param name="endInstruction">exclusive (this is where our codepath returns to)</param> /// <returns></returns> private static CodePath ExtractPath(string identifier, CodePath parentPath, HLInstruction parentExitInstruction, HLInstruction startInstruction, HLInstruction endInstruction) { CodePath toPath = CreateCodePath(identifier, startInstruction.Instruction.Offset, parentPath); toPath.ParentCodePath = parentPath; toPath.ParentExitInstruction = parentExitInstruction; HLInstruction hlInstruction = startInstruction; while (true) { parentPath.InstructionMap.Remove(hlInstruction.Instruction.Offset); hlInstruction.ParentCodePath = toPath; toPath.InstructionMap.Add(hlInstruction.Instruction.Offset, hlInstruction); if (hlInstruction.NextInstruction == null || hlInstruction.NextInstruction == endInstruction) { hlInstruction.NextInstruction = null; break; } hlInstruction = hlInstruction.NextInstruction; } if (startInstruction.PreviousInstruction != null) { startInstruction.PreviousInstruction.NextInstruction = endInstruction; } else { parentPath.StartInstruction = endInstruction; if (endInstruction != null) { parentPath.StartOffset = endInstruction.Instruction.Offset; } } if (endInstruction != null) { endInstruction.PreviousInstruction = startInstruction.PreviousInstruction; } if (endInstruction == null) { parentPath.EndInstruction = startInstruction.PreviousInstruction; if (parentPath.EndInstruction != null) { parentPath.EndOffset = parentPath.EndInstruction.Instruction.Offset + parentPath.EndInstruction.Instruction.InstructionLength; } else { parentPath.EndOffset = parentPath.StartOffset; } } startInstruction.PreviousInstruction = null; toPath.StartInstruction = startInstruction; toPath.EndInstruction = hlInstruction; toPath.EndOffset = hlInstruction.Instruction.Offset + hlInstruction.Instruction.InstructionLength; if (endInstruction != null && parentPath == endInstruction.ParentCodePath) { toPath.ParentEntryInstruction = endInstruction; } else { toPath.ParentEntryInstruction = null; } return toPath; }
private bool IsCodePathAnIfPath(CodePath path) { HLInstruction instruction = path.GetFirstInstruction(); bool foundOneIf = false; while (instruction != null) { if (instruction.IsConditionalBranch && instruction.ProcessedStackValue != null) { foundOneIf = true; } else { if (instruction.ProcessedStackValue != null) { return false; } } instruction = instruction.GetNextInstruction(); } return foundOneIf; }
private void AnalyzeCodePath(Stack <StackValue> stack, CodePath path, ref int tempVarIndex) { HLInstruction instruction = path.GetFirstInstruction(); while (instruction != null) { try { if (instruction.BranchFunction != null) { if (!instruction.Instruction.HasStackUsageInfo) { instruction.Instruction.StackIn = instruction.BranchFunction.ParameterCount; instruction.Instruction.StackOut = instruction.BranchFunction.ReturnCount; instruction.Instruction.StackLeftOver = 0; instruction.Instruction.HasStackUsageInfo = true; } } if (instruction.UnconditionalBranch) { // One should not even occur //Debug.Assert(false); } else if (instruction.ExitFunction) { var value = new StackValueOperation(StackValueOperationType.Return); if (path.ParentFunction.ReturnCount > 0) { for (int i = 0; i < path.ParentFunction.ReturnCount; i++) { value.Operands.Add(stack.Pop()); } } instruction.ProcessedStackValue = value; } else if (instruction.IsConditionalBranch || instruction.IsSwitchBranch) { instruction.ProcessedStackValue = stack.Pop(); } else { bool processDefault = false; StackValueOperation operationValue = null; StackValue tempAnyValue; StackValueOperation tempOpValue; StackValueLiteral tempLiteralValue; StackValuePointerBase tempPointerValue; OpCode opCode = instruction.Instruction.OpCode; switch (opCode) { case OpCode.AddVec: VectorOperation(StackValueOperationType.Add, stack); break; case OpCode.SubVec: VectorOperation(StackValueOperationType.Sub, stack); break; case OpCode.MulVec: VectorOperation(StackValueOperationType.Mul, stack); break; case OpCode.DivVec: VectorOperation(StackValueOperationType.Div, stack); break; case OpCode.NegVec: VectorOperation(StackValueOperationType.Neg, stack); break; case OpCode.VecFromF: VectorOperation(StackValueOperationType.FromF, stack); break; case OpCode.PushS: stack.Push(new StackValueLiteral((short)instruction.Instruction.Operands[0])); break; case OpCode.Push: stack.Push(new StackValueLiteral((int)(uint)instruction.Instruction.Operands[0])); break; case OpCode.PushF: stack.Push(new StackValueLiteral((float)instruction.Instruction.Operands[0])); break; case OpCode.PushString: stack.Push(new StackValueLiteral((string)instruction.Instruction.Operands[0])); break; case OpCode.Dup: stack.Push(stack.Peek()); break; case OpCode.Pop: tempOpValue = stack.Peek() as StackValueOperation; if (tempOpValue != null && tempOpValue.OperationType == StackValueOperationType.Call) { operationValue = new StackValueOperation(StackValueOperationType.Pop); processDefault = true; } break; case OpCode.CallNative: operationValue = new StackValueOperation(instruction.Instruction.Operands[2].ToString()); processDefault = true; break; case OpCode.Call: operationValue = new StackValueOperation(instruction.BranchFunction.Name); processDefault = true; break; case OpCode.RefGet: stack.Push(new StackValueDeref(stack.Pop())); break; case OpCode.RefSet: instruction.ProcessedStackValue = new StackValueAssign(PopPointer(stack), stack.Pop()); break; case OpCode.RefPeekSet: tempAnyValue = stack.Pop(); // value! instruction.ProcessedStackValue = new StackValueAssign(PeekPointer(stack), tempAnyValue); break; case OpCode.ArrayExplode: // This is used to either pass a structure to a native/function call // or to explode the variables onto the stack to do a "shallow-copy" tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var explodeCount = (int)tempLiteralValue.Value; for (int i = 0; i < explodeCount; i++) { stack.Push(new StackValueDeref(new StackValuePointerIndex(tempPointerValue, i))); } break; case OpCode.ArrayImplode: // The only case this is ever used is for a shallow copy! tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var tempStack = new Stack <StackValue>(); var implodeCount = (int)tempLiteralValue.Value; for (int i = implodeCount - 1; i >= 0; i--) { tempStack.Push( new StackValueAssign(new StackValuePointerIndex(tempPointerValue, i), stack.Pop())); } var stackValueGroup = new ProcessedStackValueGroup(); stackValueGroup.Values.AddRange(tempStack.ToArray()); instruction.ProcessedStackValue = stackValueGroup; break; case OpCode.Var0: case OpCode.Var1: case OpCode.Var2: case OpCode.Var3: case OpCode.Var4: case OpCode.Var5: case OpCode.Var6: case OpCode.Var7: stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (opCode - OpCode.Var0))); break; case OpCode.Var: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (int)tempLiteralValue.Value)); break; case OpCode.LocalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Local, (int)tempLiteralValue.Value)); break; case OpCode.GlobalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Global, (int)tempLiteralValue.Value)); break; case OpCode.ArrayRef: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; tempAnyValue = stack.Pop(); Debug.Assert(tempPointerValue != null); Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerArray(tempPointerValue, tempAnyValue, (int)tempLiteralValue.Value)); break; case OpCode.NullObj: stack.Push(new StackValuePointerVar(StackValuePointerType.Null)); break; case OpCode.Add: // Special case for pointer add tempAnyValue = stack.Pop(); tempPointerValue = stack.Peek() as StackValuePointerBase; if (tempPointerValue != null) { stack.Pop(); // tempPointerValue tempLiteralValue = tempAnyValue as StackValueLiteral; Debug.Assert(tempLiteralValue != null && (int)tempLiteralValue.Value % 4 == 0); stack.Push(new StackValuePointerIndex(tempPointerValue, (int)tempLiteralValue.Value / 4)); } else { stack.Push(tempAnyValue); operationValue = new StackValueOperation(opCode); processDefault = true; } break; case OpCode.StrCat: case OpCode.StrCatI: case OpCode.StrCpy: case OpCode.IntToStr: operationValue = new StackValueStringOperation(opCode, (byte)instruction.Instruction.Operands[0]); processDefault = true; break; case OpCode.StrVarCpy: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var targetSize = (uint)(int)tempLiteralValue.Value; tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var sourceSize = (uint)(int)tempLiteralValue.Value; var popSize = sourceSize; tempAnyValue = PopPointer(stack); // Pop till the last one for (var i = 1; i < popSize; i++) { tempAnyValue = PopPointer(stack); } operationValue = new StackValueStringOperation(opCode, targetSize, sourceSize); operationValue.Operands.Add(new StackValueRef(tempAnyValue)); // 0 = source operationValue.Operands.Add(tempPointerValue); // 1 = target instruction.ProcessedStackValue = operationValue; break; case OpCode.RefProtect: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectMode = (int)tempLiteralValue.Value; Debug.Assert(protectMode == 1 || protectMode == 2 || protectMode == 5 || protectMode == 6); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectCount = (int)tempLiteralValue.Value; //Debug.Assert(protectCount == 1); tempPointerValue = PopPointer(stack); operationValue = new StackValueOperation(StackValueOperationType.RefProtect); operationValue.Operands.Add(tempPointerValue); operationValue.Operands.Add(tempLiteralValue); if ((protectMode & 1) != 0) { stack.Push(operationValue); } break; default: if (instruction.Instruction is InstructionPush) { // PushD special case stack.Push(new StackValueLiteral((int)instruction.Instruction.Operands[0])); } else { operationValue = new StackValueOperation(opCode); processDefault = true; } break; } if (processDefault) { Debug.Assert(instruction.Instruction.HasStackUsageInfo); var stackValues = new Stack <StackValue>(); for (int i = 0; i < instruction.Instruction.StackIn; i++) { StackValue stackItem = stack.Pop(); stackValues.Push(stackItem); } operationValue.Operands.AddRange(stackValues); if (instruction.Instruction.StackLeftOver > 0) { for (int i = 0; i < instruction.Instruction.StackLeftOver; i++) { stackValues.Push(stackValues.Pop()); } } if (instruction.Instruction.StackOut > 0) { if (instruction.Instruction.StackOut > 1) { var multiAssign = new StackValueAssignMulti(operationValue); for (int i = 0; i < instruction.Instruction.StackOut; i++) { tempPointerValue = new StackValuePointerVar(StackValuePointerType.Temporary, tempVarIndex + i); multiAssign.AssignPointers.Add(tempPointerValue); stack.Push(new StackValueDeref(tempPointerValue)); } tempVarIndex += instruction.Instruction.StackOut; instruction.ProcessedStackValue = multiAssign; } else { stack.Push(operationValue); } } else { instruction.ProcessedStackValue = operationValue; } } } } catch (Exception e) { throw new Exception( "Error while decompiling instruction : " + instruction.Instruction + "\n", e); } instruction = instruction.GetNextInstruction(); } }
private void AnalyzeCodePath(CodePath path) { HLInstruction previousInstruction = null; var branchInstructions = new List<HLInstruction>(); int offset = path.StartOffset; while (true) { if (path.ParentCodePath != null) // non main { CodePath parentPath = path.ParentFunction.DetermineCodePathFromOffset(offset); if (parentPath != null) { if (!path.IsInstructionOffsetInPathTree(offset)) { // Hmm.. so the target offset is not the current tree... which is bad // This can only mean a bad jump assumption before. We must somehow extract // The instructions from this existing path and merge it with our parent HLInstruction startInstruction = parentPath.InstructionMap[offset]; CodePath newPath = ExtractPath(path.ParentCodePath.Name + "_temp", parentPath, startInstruction.PreviousInstruction, startInstruction, null); // Now we can merge it with this path's parent CodePath targetCodePath = FindCommonPathAncestor(path, parentPath); MergePath(targetCodePath, newPath); if (parentPath.ParentCodePath == targetCodePath) { parentPath.ParentEntryInstruction = startInstruction; } else { parentPath.ParentEntryInstruction = null; } // Set some variables so we know how to break out of here. parentPath = targetCodePath; } // Okay, break out of there buddy! if (parentPath == path.ParentCodePath) { path.ParentEntryInstruction = path.ParentCodePath.GetInstruction(offset); } else { // null = we reached the end of the code path for the parent as well! path.ParentEntryInstruction = null; } break; } } Instruction instruction = Decoder.Decode(offset); offset += instruction.InstructionLength; var hlInstruction = new HLInstruction(instruction); if (instruction is InstructionFnEnd) { if (path.ParentCodePath == null) { // This means this is in the function root path.ParentFunction.EndOffset = instruction.Offset + instruction.InstructionLength; path.ParentFunction.ReturnCount = (instruction as InstructionFnEnd).ReturnCount; hlInstruction.ExitFunction = true; } else { if (instruction.Offset == path.ParentFunction.EndOffset) { // Non root code path reached end of function path.ParentEntryInstruction = null; hlInstruction.ExitFunction = true; } else { // Hmm, this must be a exit function invocation // We'll add it, and exit out of the loop later in the code hlInstruction.ExitFunction = true; } } } else if (instruction is InstructionBranch) { if (instruction.OpCode == OpCode.Call) { hlInstruction.BranchFunction = FunctionTargets[instruction.BranchOffset]; } else if (instruction.OpCode == OpCode.Jump) { if (path.ParentCodePath != null && instruction.BranchOffset < instruction.Offset && path.ParentCodePath.GetInstruction(instruction.BranchOffset) != null) { // Loop! hlInstruction.BranchLoopInstruction = path.ParentCodePath.GetInstruction(instruction.BranchOffset); hlInstruction.BranchLoopInstruction.LoopCodePath = path; // The next instruction should break us out of this codepath... hlInstruction.UnconditionalBranch = true; } else { // Okay, we'll just be naive for now and follow the jump // It is *possible* that this jump might be for an "else" or "case default" block, in which case, we are screwed. // But we will deal with this while we deal with branches hlInstruction.UnconditionalBranch = true; offset = instruction.BranchOffset; } } else { // We got a conditional branch instruction hlInstruction.IsConditionalBranch = true; branchInstructions.Add(hlInstruction); offset = instruction.BranchOffset; } } else if (instruction is InstructionSwitch) { hlInstruction.IsSwitchBranch = true; branchInstructions.Add(hlInstruction); } hlInstruction.PreviousInstruction = previousInstruction; if (previousInstruction == null) { path.StartInstruction = hlInstruction; } else { previousInstruction.NextInstruction = hlInstruction; } previousInstruction = hlInstruction; hlInstruction.ParentCodePath = path; path.InstructionMap.Add(instruction.Offset, hlInstruction); if (hlInstruction.ExitFunction) { break; // out of while loop } } path.EndInstruction = previousInstruction; path.EndOffset = offset; AnalyzeBranchInstructions(branchInstructions); }
private void AnalyzeCodePath(CodePath path) { HLInstruction previousInstruction = null; var branchInstructions = new List <HLInstruction>(); int offset = path.StartOffset; while (true) { if (path.ParentCodePath != null) // non main { CodePath parentPath = path.ParentFunction.DetermineCodePathFromOffset(offset); if (parentPath != null) { if (!path.IsInstructionOffsetInPathTree(offset)) { // Hmm.. so the target offset is not the current tree... which is bad // This can only mean a bad jump assumption before. We must somehow extract // The instructions from this existing path and merge it with our parent HLInstruction startInstruction = parentPath.InstructionMap[offset]; CodePath newPath = ExtractPath(path.ParentCodePath.Name + "_temp", parentPath, startInstruction.PreviousInstruction, startInstruction, null); // Now we can merge it with this path's parent CodePath targetCodePath = FindCommonPathAncestor(path, parentPath); MergePath(targetCodePath, newPath); if (parentPath.ParentCodePath == targetCodePath) { parentPath.ParentEntryInstruction = startInstruction; } else { parentPath.ParentEntryInstruction = null; } // Set some variables so we know how to break out of here. parentPath = targetCodePath; } // Okay, break out of there buddy! if (parentPath == path.ParentCodePath) { path.ParentEntryInstruction = path.ParentCodePath.GetInstruction(offset); } else { // null = we reached the end of the code path for the parent as well! path.ParentEntryInstruction = null; } break; } } Instruction instruction = Decoder.Decode(offset); offset += instruction.InstructionLength; var hlInstruction = new HLInstruction(instruction); if (instruction is InstructionFnEnd) { if (path.ParentCodePath == null) { // This means this is in the function root path.ParentFunction.EndOffset = instruction.Offset + instruction.InstructionLength; path.ParentFunction.ReturnCount = (instruction as InstructionFnEnd).ReturnCount; hlInstruction.ExitFunction = true; } else { if (instruction.Offset == path.ParentFunction.EndOffset) { // Non root code path reached end of function path.ParentEntryInstruction = null; hlInstruction.ExitFunction = true; } else { // Hmm, this must be a exit function invocation // We'll add it, and exit out of the loop later in the code hlInstruction.ExitFunction = true; } } } else if (instruction is InstructionBranch) { if (instruction.OpCode == OpCode.Call) { hlInstruction.BranchFunction = FunctionTargets[instruction.BranchOffset]; } else if (instruction.OpCode == OpCode.Jump) { if (path.ParentCodePath != null && instruction.BranchOffset < instruction.Offset && path.ParentCodePath.GetInstruction(instruction.BranchOffset) != null) { // Loop! hlInstruction.BranchLoopInstruction = path.ParentCodePath.GetInstruction(instruction.BranchOffset); hlInstruction.BranchLoopInstruction.LoopCodePath = path; // The next instruction should break us out of this codepath... hlInstruction.UnconditionalBranch = true; } else { // Okay, we'll just be naive for now and follow the jump // It is *possible* that this jump might be for an "else" or "case default" block, in which case, we are screwed. // But we will deal with this while we deal with branches hlInstruction.UnconditionalBranch = true; offset = instruction.BranchOffset; } } else { // We got a conditional branch instruction hlInstruction.IsConditionalBranch = true; branchInstructions.Add(hlInstruction); offset = instruction.BranchOffset; } } else if (instruction is InstructionSwitch) { hlInstruction.IsSwitchBranch = true; branchInstructions.Add(hlInstruction); } hlInstruction.PreviousInstruction = previousInstruction; if (previousInstruction == null) { path.StartInstruction = hlInstruction; } else { previousInstruction.NextInstruction = hlInstruction; } previousInstruction = hlInstruction; hlInstruction.ParentCodePath = path; path.InstructionMap.Add(instruction.Offset, hlInstruction); if (hlInstruction.ExitFunction) { break; // out of while loop } } path.EndInstruction = previousInstruction; path.EndOffset = offset; AnalyzeBranchInstructions(branchInstructions); }
private void ProcessCodePath(TextWriter writer, CodePath path, string indent) { HLInstruction instruction = path.GetFirstInstruction(); while (instruction != null) { if (instruction.IsConditionalBranch) { writer.WriteLine(string.Format("{0}if ({1})", indent, instruction.DefaultConditional ? "true" : "false")); writer.WriteLine(indent + "{"); ProcessCodePath(writer, instruction.BranchCodesPaths[instruction.DefaultConditional], indent + " "); writer.WriteLine(indent + "}"); if (instruction.BranchCodesPaths.ContainsKey(!instruction.DefaultConditional)) { CodePath elsePath = instruction.BranchCodesPaths[!instruction.DefaultConditional]; if (elsePath.StartInstruction != null) { writer.WriteLine(indent + "else"); writer.WriteLine(indent + "{"); ProcessCodePath(writer, elsePath, indent + " "); writer.WriteLine(indent + "}"); } } } else if (instruction.IsSwitchBranch) { // Do switch cases ever fall through?? I'm assuming they don't here! writer.WriteLine(indent + "switch"); writer.WriteLine(indent + "{"); // Keep track of code paths are have already outputted to keep // track of offsets that lead to the same codepath var swDonePaths = new List<CodePath>(); foreach (var item in instruction.BranchCodesPaths) { if (swDonePaths.Contains(item.Value)) { continue; } foreach (var item2 in instruction.BranchCodesPaths) { // O(n^2) loop here, there's probably a better way to optimize it if (item2.Value == item.Value) { if (item2.Key.GetType() == typeof (int)) { writer.WriteLine(string.Format("{0} case {1}:", indent, item2.Key)); } else { writer.WriteLine(string.Format("{0} default:", indent, item2.Key)); } } } writer.WriteLine(indent + " {"); ProcessCodePath(writer, item.Value, indent + " "); if (item.Value.EndInstruction == null || !item.Value.EndInstruction.ExitFunction) { writer.WriteLine(indent + " break"); } writer.WriteLine(indent + " }"); swDonePaths.Add(item.Value); } writer.WriteLine(indent + "}"); } else if (instruction.LoopCodePath != null) { // First of a loop instruction (hopefully, someday, this will be extracted out by the ProgramAnalyzer) // Can we ever break out of a loop? I assume we can't here! writer.WriteLine(indent + "while"); writer.WriteLine(indent + "("); instruction = WriteLoopConditional(writer, instruction, indent + " "); writer.WriteLine(indent + ")"); writer.WriteLine(indent + "{"); ProcessCodePath(writer, instruction.BranchCodesPaths[true], indent + " "); writer.WriteLine(indent + "}"); } else { WriteInstruction(writer, instruction, indent); } instruction = instruction.GetNextInstruction(); } }
private void AnalyzeCodePath(Stack<StackValue> stack, CodePath path, ref int tempVarIndex) { HLInstruction instruction = path.GetFirstInstruction(); while (instruction != null) { try { if (instruction.BranchFunction != null) { if (!instruction.Instruction.HasStackUsageInfo) { instruction.Instruction.StackIn = instruction.BranchFunction.ParameterCount; instruction.Instruction.StackOut = instruction.BranchFunction.ReturnCount; instruction.Instruction.StackLeftOver = 0; instruction.Instruction.HasStackUsageInfo = true; } } if (instruction.UnconditionalBranch) { // One should not even occur //Debug.Assert(false); } else if (instruction.ExitFunction) { var value = new StackValueOperation(StackValueOperationType.Return); if (path.ParentFunction.ReturnCount > 0) { for (int i = 0; i < path.ParentFunction.ReturnCount; i++) { value.Operands.Add(stack.Pop()); } } instruction.ProcessedStackValue = value; } else if (instruction.IsConditionalBranch || instruction.IsSwitchBranch) { instruction.ProcessedStackValue = stack.Pop(); } else { bool processDefault = false; StackValueOperation operationValue = null; StackValue tempAnyValue; StackValueOperation tempOpValue; StackValueLiteral tempLiteralValue; StackValuePointerBase tempPointerValue; OpCode opCode = instruction.Instruction.OpCode; switch (opCode) { case OpCode.AddVec: VectorOperation(StackValueOperationType.Add, stack); break; case OpCode.SubVec: VectorOperation(StackValueOperationType.Sub, stack); break; case OpCode.MulVec: VectorOperation(StackValueOperationType.Mul, stack); break; case OpCode.DivVec: VectorOperation(StackValueOperationType.Div, stack); break; case OpCode.NegVec: VectorOperation(StackValueOperationType.Neg, stack); break; case OpCode.VecFromF: VectorOperation(StackValueOperationType.FromF, stack); break; case OpCode.PushS: stack.Push(new StackValueLiteral((short) instruction.Instruction.Operands[0])); break; case OpCode.Push: stack.Push(new StackValueLiteral((int) (uint) instruction.Instruction.Operands[0])); break; case OpCode.PushF: stack.Push(new StackValueLiteral((float) instruction.Instruction.Operands[0])); break; case OpCode.PushString: stack.Push(new StackValueLiteral((string) instruction.Instruction.Operands[0])); break; case OpCode.Dup: stack.Push(stack.Peek()); break; case OpCode.Pop: tempOpValue = stack.Peek() as StackValueOperation; if (tempOpValue != null && tempOpValue.OperationType == StackValueOperationType.Call) { operationValue = new StackValueOperation(StackValueOperationType.Pop); processDefault = true; } break; case OpCode.CallNative: operationValue = new StackValueOperation(instruction.Instruction.Operands[2].ToString()); processDefault = true; break; case OpCode.Call: operationValue = new StackValueOperation(instruction.BranchFunction.Name); processDefault = true; break; case OpCode.RefGet: stack.Push(new StackValueDeref(stack.Pop())); break; case OpCode.RefSet: instruction.ProcessedStackValue = new StackValueAssign(PopPointer(stack), stack.Pop()); break; case OpCode.RefPeekSet: tempAnyValue = stack.Pop(); // value! instruction.ProcessedStackValue = new StackValueAssign(PeekPointer(stack), tempAnyValue); break; case OpCode.ArrayExplode: // This is used to either pass a structure to a native/function call // or to explode the variables onto the stack to do a "shallow-copy" tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var explodeCount = (int) tempLiteralValue.Value; for (int i = 0; i < explodeCount; i++) { stack.Push(new StackValueDeref(new StackValuePointerIndex(tempPointerValue, i))); } break; case OpCode.ArrayImplode: // The only case this is ever used is for a shallow copy! tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var tempStack = new Stack<StackValue>(); var implodeCount = (int) tempLiteralValue.Value; for (int i = implodeCount - 1; i >= 0; i--) { tempStack.Push( new StackValueAssign(new StackValuePointerIndex(tempPointerValue, i), stack.Pop())); } var stackValueGroup = new ProcessedStackValueGroup(); stackValueGroup.Values.AddRange(tempStack.ToArray()); instruction.ProcessedStackValue = stackValueGroup; break; case OpCode.Var0: case OpCode.Var1: case OpCode.Var2: case OpCode.Var3: case OpCode.Var4: case OpCode.Var5: case OpCode.Var6: case OpCode.Var7: stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (opCode - OpCode.Var0))); break; case OpCode.Var: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (int) tempLiteralValue.Value)); break; case OpCode.LocalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Local, (int) tempLiteralValue.Value)); break; case OpCode.GlobalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Global, (int) tempLiteralValue.Value)); break; case OpCode.ArrayRef: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; tempAnyValue = stack.Pop(); Debug.Assert(tempPointerValue != null); Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerArray(tempPointerValue, tempAnyValue, (int) tempLiteralValue.Value)); break; case OpCode.NullObj: stack.Push(new StackValuePointerVar(StackValuePointerType.Null)); break; case OpCode.Add: // Special case for pointer add tempAnyValue = stack.Pop(); tempPointerValue = stack.Peek() as StackValuePointerBase; if (tempPointerValue != null) { stack.Pop(); // tempPointerValue tempLiteralValue = tempAnyValue as StackValueLiteral; Debug.Assert(tempLiteralValue != null && (int) tempLiteralValue.Value%4 == 0); stack.Push(new StackValuePointerIndex(tempPointerValue, (int) tempLiteralValue.Value/4)); } else { stack.Push(tempAnyValue); operationValue = new StackValueOperation(opCode); processDefault = true; } break; case OpCode.StrCat: case OpCode.StrCatI: case OpCode.StrCpy: case OpCode.IntToStr: operationValue = new StackValueStringOperation(opCode, (byte)instruction.Instruction.Operands[0]); processDefault = true; break; case OpCode.StrVarCpy: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var targetSize = (uint)(int)tempLiteralValue.Value; tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var sourceSize = (uint)(int)tempLiteralValue.Value; var popSize = sourceSize; tempAnyValue = PopPointer(stack); // Pop till the last one for (var i = 1; i < popSize; i++) { tempAnyValue = PopPointer(stack); } operationValue = new StackValueStringOperation(opCode, targetSize, sourceSize); operationValue.Operands.Add(new StackValueRef(tempAnyValue)); // 0 = source operationValue.Operands.Add(tempPointerValue); // 1 = target instruction.ProcessedStackValue = operationValue; break; case OpCode.RefProtect: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectMode = (int)tempLiteralValue.Value; Debug.Assert(protectMode == 1 || protectMode == 2 || protectMode == 5 || protectMode == 6); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectCount = (int)tempLiteralValue.Value; //Debug.Assert(protectCount == 1); tempPointerValue = PopPointer(stack); operationValue = new StackValueOperation(StackValueOperationType.RefProtect); operationValue.Operands.Add(tempPointerValue); operationValue.Operands.Add(tempLiteralValue); if ((protectMode & 1) != 0) { stack.Push(operationValue); } break; default: if (instruction.Instruction is InstructionPush) { // PushD special case stack.Push(new StackValueLiteral((int) instruction.Instruction.Operands[0])); } else { operationValue = new StackValueOperation(opCode); processDefault = true; } break; } if (processDefault) { Debug.Assert(instruction.Instruction.HasStackUsageInfo); var stackValues = new Stack<StackValue>(); for (int i = 0; i < instruction.Instruction.StackIn; i++) { StackValue stackItem = stack.Pop(); stackValues.Push(stackItem); } operationValue.Operands.AddRange(stackValues); if (instruction.Instruction.StackLeftOver > 0) { for (int i = 0; i < instruction.Instruction.StackLeftOver; i++) { stackValues.Push(stackValues.Pop()); } } if (instruction.Instruction.StackOut > 0) { if (instruction.Instruction.StackOut > 1) { var multiAssign = new StackValueAssignMulti(operationValue); for (int i = 0; i < instruction.Instruction.StackOut; i++) { tempPointerValue = new StackValuePointerVar(StackValuePointerType.Temporary, tempVarIndex + i); multiAssign.AssignPointers.Add(tempPointerValue); stack.Push(new StackValueDeref(tempPointerValue)); } tempVarIndex += instruction.Instruction.StackOut; instruction.ProcessedStackValue = multiAssign; } else { stack.Push(operationValue); } } else { instruction.ProcessedStackValue = operationValue; } } } } catch (Exception e) { throw new Exception( "Error while decompiling instruction : " + instruction.Instruction + "\n", e); } instruction = instruction.GetNextInstruction(); } }
private static CodePath CreateCodePath(string identifier, int startOffset, CodePath parentPath) { CodePath path = parentPath.ParentFunction.CreateCodePath(string.Format("{0}_{1:x}", identifier, startOffset)); path.ParentCodePath = parentPath; path.StartOffset = startOffset; return path; }