static void Main(string[] args) { Console.WriteLine(">> Loading configuration options..."); if (!Config.Load(args)) return; if (Config.NoCmsg && Config.NoSmsg) { Logger.WriteConsoleLine("Please give me something to do."); Config.ShowHelp(); return; } Logger.CreateOutputStream(Config.OutputFile); Console.WriteLine(">> Opening Wow client..."); ClientStream = new BinaryReader(File.OpenRead(Config.Executable)); if (!BaseStream.CanRead) return; ClientBytes = File.ReadAllBytes(Config.Executable); Disasm = new UnmanagedBuffer(ClientBytes); Env = Emulator.Create(BaseStream); if (!Config.NoSmsg) { Console.WriteLine(">> Discovering JAM groups..."); foreach (var pattern in ClientGroupPatterns) // Load jam groups... { var offsets = ClientBytes.FindPattern(pattern, 0xFF); if (offsets.Count == 0) { Console.WriteLine(@"Could not find group name "" {0}""", System.Text.Encoding.ASCII.GetString(pattern.Skip(1).ToArray())); return; } else { Console.WriteLine(@"Found JAM Group "" {0}""", System.Text.Encoding.ASCII.GetString(pattern.Skip(1).ToArray())); Dispatchers.Add(new JamDispatch((int)(offsets[0] + 1))); } } } if (!Config.NoGhNames && !Opcodes.TryPopulate()) return; if (!Config.NoSmsg) SMSG.Dump(); if (!Config.NoCmsg) CMSG.Dump(Config.SpecificOpcodeValue); }
static void Main(string[] args) { try { Console.WriteLine(">> Loading configuration options..."); if (!Config.Load(args)) { return; } if (Config.NoCmsg && Config.NoSmsg) { Logger.WriteConsoleLine("Please give me something to do."); Config.ShowHelp(); return; } if ((Config.BinDiff == string.Empty) != (Config.Opcode == string.Empty)) { Console.WriteLine("ERROR: -d and -o flags need to be both present to function!"); return; } if (Config.BinDiff != string.Empty && Config.Opcode != string.Empty) { Console.WriteLine(">> Opening Diff..."); FuncDiff = new BinDiff(Config.BinDiff); if (!FuncDiff.openConnection()) { Console.WriteLine(">> Failed to open diff!"); return; } Console.WriteLine(">> Opening OpcodeTable..."); OpTable = new OpcodeTable(Config.Opcode); if (!OpTable.openConnection()) { Console.WriteLine(">> Failed to open OpcodeTable!"); return; } } if (Logger.CreateOutputStream(Config.OutputFile)) { Logger.PrepOutputStram(); } Console.WriteLine(">> Opening Wow client..."); ClientStream = new BinaryReader(File.OpenRead(Config.Executable)); if (!BaseStream.CanRead) { return; } ClientBytes = File.ReadAllBytes(Config.Executable); Disasm = new UnmanagedBuffer(ClientBytes); Environment = Emulator.Create(BaseStream); ClientBuild = new Dumpers.Build(); Logger.WriteLine("Detected build {0}.{1}", ClientBuild.Version, ClientBuild.BuildNumber); switch (ClientBuild.isBuildSupported()) { case Dumpers.BuildSupport.BUILD_UNKOWN: Console.WriteLine("\nBuild not yet implemented!\nThere might be unexpected results running opcodedumper."); break; case Dumpers.BuildSupport.BUILD_UNSUPPORTED: Console.WriteLine("\nBuild unsupported!\nNameOffset has changed since this build. You can try using an old version."); return; case Dumpers.BuildSupport.BUILD_SUPPORTED: Console.WriteLine("Build Supported!"); break; } Console.WriteLine(">> Discovering JAM groups..."); foreach (var pattern in ClientGroupPatterns) // Load jam groups... { var offsets = ClientBytes.FindPattern(pattern, 0xFF); if (offsets.Count == 0) { Console.WriteLine(@"Could not find group name "" {0}""", System.Text.Encoding.ASCII.GetString(pattern.Skip(1).ToArray())); return; } else { Console.WriteLine(@"Found JAM Group "" {0}""", System.Text.Encoding.ASCII.GetString(pattern.Skip(1).ToArray())); var dispatch = new JamDispatch((int)(offsets[0] + 1)); Dispatchers[dispatch.GetGroup()] = dispatch; } } if (!Config.NoGhNames && !Opcodes.TryPopulate()) { return; } if (!Config.NoSmsg) { Dumpers.SMSG.Dump(); } if (!Config.NoCmsg) { Dumpers.CMSG.Dump(Config.SpecificOpcodeValue); } if (Config.WPP) { Dumpers.CMSG.dumpWPPFile("Opcodes.cs"); } } catch (SystemException e) { Console.WriteLine("Caught level exception: \n{0}\n\nDid you use the correct command line arguments? Use -help to show usage.\nPress any key to exit...", e.Message); Console.ReadKey(); } }
private bool ExecuteASM(Disasm disasm, UnmanagedBuffer buffer, bool followCalls) { if (Interrupted) return false; var entryPoint = buffer.Ptr.ToInt32(); var disassemblyString = disasm.CompleteInstr; // Sanitize the instruction. if (disassemblyString.IndexOf(";") != -1) disassemblyString = disassemblyString.Remove(disassemblyString.IndexOf(";")); disassemblyString = Regex.Replace(disassemblyString, @"\s+", " ", RegexOptions.IgnoreCase).Trim(); if (Regex.IsMatch(disassemblyString, @"[!@#$%^&()={}\\|/?<>.~`""'_]")) return false; if (disassemblyString.Length == 0 || disassemblyString.EndsWith(":")) return false; var tokens = disassemblyString.Split(' '); var mnemonic = tokens[0]; //Console.WriteLine("0x{0:X8} {1}", disasm.EIP.ToInt64(), disasm.CompleteInstr); if (disassemblyString.Contains("call far") || disassemblyString.Contains("xmm")) return false; List<InstructionArgument> arguments = new List<InstructionArgument>(); // TODO Support for floating point opcodes var parametersList = disassemblyString.Replace(mnemonic, String.Empty).Trim().Split(new char[]{ ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (var parameter in parametersList) arguments.Add(new InstructionArgument(this, parameter.Trim())); if (mnemonic[0] == 'j') { if (ExecuteJump(disassemblyString, disasm, mnemonic)) { var jumpOffset = arguments[0].GetValue(); if (arguments[0].Type == ArgumentType.Memory) jumpOffset += (uint)entryPoint - 0x400C00; disasm.EIP = new IntPtr(jumpOffset); return true; } else return false; } else { InstructionArgument src = null; InstructionArgument dst = null; InstructionArgument extra = null; if (parametersList.Length == 1) dst = src = arguments[0]; else if (parametersList.Length == 2) { dst = arguments[0]; src = arguments[1]; } else if (parametersList.Length == 3) extra = arguments[2]; switch (mnemonic) { case "ret": case "retn": // Actually use the stack here. if (JumpBacks.Count > 0) { Pop(4); disasm.EIP = new IntPtr(JumpBacks[0]); JumpBacks.RemoveAt(0); return true; } return false; case "leave": break; case "nop": break; #region Data transfer case "mov": if (parametersList.Length != 2 || dst.Type == ArgumentType.Immediate) break; if (src.Type == ArgumentType.Immediate && src.Size > dst.Size) break; if (src.Type != ArgumentType.Immediate && src.Size != dst.Size) break; dst.SetValue(src.GetValue()); break; case "movzx": { if (parametersList.Length != 2 || dst.Type != ArgumentType.Register || src.Type == ArgumentType.Immediate || src.Size >= dst.Size) break; //! TODO Unhack this - Handles indirect jumptables //! TODO: Really need to fix memory - this superbly fails now //if (dst.Register == null) //{ /*if (src.Size == 4) addr = buffer.ReadDword(src.Address - 0x400C00); else if (src.Size == 2) addr = (uint)buffer.ReadWord(src.Address - 0x400C00); else if (src.Size == 1) addr = (uint)buffer.ReadByte(src.Address - 0x400C00);*/ //} dst.SetValue(src.GetValue()); break; } case "movsb": WriteByteToMemory(Edi.Value, ReadByteFromMemory(Esi.Value)); Ecx.Value--; if (EFlags.HasFlag(EFlags.DirectionFlag)) { Edi.Value--; Esi.Value--; } else { Edi.Value++; Esi.Value++; } break; case "movsw": WriteWordToMemory(Edi.Value, ReadWordFromMemory(Esi.Value)); Ecx.Value--; if (EFlags.HasFlag(EFlags.DirectionFlag)) { Edi.Value -= 2; Esi.Value -= 2; } else { Edi.Value += 2; Esi.Value += 2; } break; case "movsd": WriteDwordToMemory(Edi.Value, ReadDwordFromMemory(Esi.Value)); Ecx.Value--; if (EFlags.HasFlag(EFlags.DirectionFlag)) { Edi.Value -= 4; Esi.Value -= 4; } else { Edi.Value += 4; Esi.Value += 4; } break; case "stosb": WriteByteToMemory(Edi.Value, Eax.Al); Ecx.Value--; if (EFlags.HasFlag(EFlags.DirectionFlag)) { Edi.Value--; Esi.Value--; } else { Edi.Value++; Esi.Value++; } break; case "stosw": WriteWordToMemory(Edi.Value, Eax.Ax); Ecx.Value--; if (EFlags.HasFlag(EFlags.DirectionFlag)) { Edi.Value -= 2; Esi.Value -= 2; } else { Edi.Value += 2; Esi.Value += 2; } break; case "stosd": WriteDwordToMemory(Edi.Value, Eax.Value); Ecx.Value--; if (EFlags.HasFlag(EFlags.DirectionFlag)) { Edi.Value -= 4; Esi.Value -= 4; } else { Edi.Value += 4; Esi.Value += 4; } break; case "xchg": if (parametersList.Length != 2 || dst.Type != ArgumentType.Register || src.Type == ArgumentType.Immediate || src.Size != dst.Size) break; uint tmp = src.GetValue(); src.SetValue(dst.GetValue()); dst.SetValue(tmp); break; case "lea": if (parametersList.Length == 2 && dst.Type == ArgumentType.Register && src.Type == ArgumentType.Memory && src.Size > 1) dst.SetValue(src.Address); break; #endregion #region Basic maths case "inc": if (parametersList.Length == 1 && dst.Type != ArgumentType.Immediate) { ulong val = (ulong)dst.GetValue() + 1; UpdateFlags(val, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.ParityFlag); dst.SetValue((uint)val); } break; case "dec": if (parametersList.Length == 1 && dst.Type != ArgumentType.Immediate) { ulong val = (ulong)dst.GetValue() - 1; UpdateFlags(val, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.ParityFlag); dst.SetValue((uint)val); } break; case "not": if (parametersList.Length == 1 && dst.Type != ArgumentType.Immediate) dst.SetValue(~dst.GetValue()); break; case "neg": if (parametersList.Length == 1 && dst.Type != ArgumentType.Immediate) { ulong val = (ulong)(-(long)dst.GetValue()); UpdateFlags(val, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.ParityFlag | EFlags.CarryFlag); dst.SetValue((uint)val); } break; case "bswap": if (parametersList.Length != 1 || dst.Type != ArgumentType.Register || dst.Size != 4) break; uint dval = dst.GetValue(); dst.SetValue((uint)((dval << 24) | ((dval & 0xFF00) << 8) | ((dval & 0xFF0000) >> 8) | (dval >> 24))); break; case "add": if (parametersList.Length == 2) { ulong val = (ulong)dst.GetValue() + src.GetValue(); UpdateFlags(val, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.ParityFlag | EFlags.CarryFlag); dst.SetValue((uint)val); } break; case "sub": if (parametersList.Length == 2) { ulong val = (ulong)dst.GetValue() - (ulong)src.GetValue(); UpdateFlags(val, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.ParityFlag | EFlags.CarryFlag); dst.SetValue((uint)val); } break; case "mul": // unsigned multiply // The OF and CF flags are set to 0 if the upper half of the result is 0, otherwise they are set to 1 if (parametersList.Length != 1 || src.Type == ArgumentType.Immediate) break; switch (src.Size) { case 1: ushort r16 = (ushort)(Eax.Al * src.GetValue()); Eax.Ax = r16; ToggleFlagIf(EFlags.OverflowFlag | EFlags.CarryFlag, (r16 >> 8) == 0); break; case 2: uint r32 = Eax.Ax * src.GetValue(); Edx.Dx = (ushort)(r32 >> 16); // high order Eax.Ax = (ushort)(r32 & 0xFFFF); // low order ToggleFlagIf(EFlags.OverflowFlag | EFlags.CarryFlag, Edx.Dx == 0); break; case 4: ulong r64 = Eax.Ax * src.GetValue(); Edx.Value = (uint)(r64 >> 32); // high order Eax.Value = (uint)(r64 & 0xFFFFFFFF); // low order ToggleFlagIf(EFlags.OverflowFlag | EFlags.CarryFlag, Edx.Value == 0); break; } break; case "div": if (src.Type == ArgumentType.Immediate) break; ulong dividend, quotient; uint divisor = src.GetValue(); if (divisor == 0) break; if (src.Size == 1) { dividend = Eax.Ax; quotient = dividend / divisor; if (quotient > 0xFF) break; Eax.Al = (byte)quotient; Eax.Ah = (byte)(dividend % divisor); } else if (src.Size == 2) { dividend = ((uint)Edx.Dx << 16) & Eax.Ax; quotient = dividend / divisor; if (quotient > 0xFFFF) break; Eax.Ax = (ushort)quotient; Edx.Dx = (ushort)(dividend % divisor); } else if (src.Size == 4) { dividend = ((ulong)Edx.Value << 32) & Eax.Value; quotient = dividend / divisor; if (quotient > 0xFFFFFFFF) break; Eax.Value = (uint)quotient; Edx.Value = (uint)(dividend % divisor); } break; case "imul": // Signed multiply case "idiv": // Signed division break; // NYI #endregion #region Bitwise operators case "and": if (parametersList.Length == 2) { uint result = dst.GetValue() & src.GetValue(); dst.SetValue(result); ClearFlags(EFlags.OverflowFlag | EFlags.CarryFlag); UpdateFlags(result, dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag); } break; case "or": if (parametersList.Length == 2) { uint result = dst.GetValue() | src.GetValue(); dst.SetValue(result); ClearFlags(EFlags.OverflowFlag | EFlags.CarryFlag); UpdateFlags(result, dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag); } else throw new ArgumentException(); break; case "xor": if (parametersList.Length == 2) { uint result = dst.GetValue() ^ src.GetValue(); dst.SetValue(result); ClearFlags(EFlags.OverflowFlag | EFlags.CarryFlag); UpdateFlags(result, dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag); } break; case "stc": // set carry flag SetFlags(EFlags.CarryFlag); break; case "std": // set direction flag SetFlags(EFlags.DirectionFlag); break; case "clc": // clear carry flag ClearFlags(EFlags.CarryFlag); break; case "cld": // clear direction flag ClearFlags(EFlags.DirectionFlag); break; case "shr": // shift right { if (parametersList.Length != 2 || dst.Type == ArgumentType.Immediate || src.Type == ArgumentType.Memory || (src.Type == ArgumentType.Register && src.RegisterName != "cl")) break; uint result = dst.GetValue() >> (byte)src.GetValue(); dst.SetValue(result); if (src.Type == ArgumentType.Immediate && src.GetValue() == 1) UpdateFlags(result, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag | EFlags.CarryFlag); else UpdateFlags(result, dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag | EFlags.CarryFlag); break; } case "shl": // shift left case "sal": // shift arithmetic left (signed) { if (parametersList.Length != 2 || dst.Type == ArgumentType.Immediate || src.Type == ArgumentType.Memory || (src.Type == ArgumentType.Register && src.RegisterName != "cl")) break; ulong result = (ulong)dst.GetValue() << (byte)src.GetValue(); dst.SetValue((uint)result); if (src.Type == ArgumentType.Immediate && src.GetValue() == 1) UpdateFlags(result, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag | EFlags.CarryFlag); else UpdateFlags(result, dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag | EFlags.CarryFlag); break; } case "sar": // shift arithmetic right (signed) { if (parametersList.Length != 2 || dst.Type == ArgumentType.Immediate || src.Type == ArgumentType.Memory || (src.Type == ArgumentType.Register && src.RegisterName != "cl")) break; uint result = (uint)((int)dst.GetValue() >> (byte)src.GetValue()); dst.SetValue(result); if (src.Type == ArgumentType.Immediate && src.GetValue() == 1) UpdateFlags(result, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag | EFlags.CarryFlag); else UpdateFlags(result, dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag | EFlags.CarryFlag); break; } case "ror": // rotate right { // bits >> n | (bits << (32 - n)); uint data = dst.GetValue(); uint bitsToShift = src.GetValue(); data = data >> (int)bitsToShift | (data << (32 - (int)bitsToShift)); dst.SetValue(data); if (src.Type == ArgumentType.Immediate && src.GetValue() == 1) UpdateFlags(data, dst.Size, EFlags.OverflowFlag | EFlags.CarryFlag); else UpdateFlags(data, dst.Size, EFlags.CarryFlag); break; } case "rol": // rotate left { // bits << n | (bits >> (32 - n)); uint data2 = dst.GetValue(); uint bitsToShift2 = src.GetValue(); uint data = data2 << (int)bitsToShift2 | (data2 >> (32 - (int)bitsToShift2)); dst.SetValue(data); if (src.Type == ArgumentType.Immediate && src.GetValue() == 1) UpdateFlags(data, dst.Size, EFlags.OverflowFlag | EFlags.CarryFlag); else UpdateFlags(data, dst.Size, EFlags.CarryFlag); break; } #endregion case "call": // TODO Use the stack to keep s and r (saved registers (0) and jumpback offset (+4)) // TODO Half done. (see below) var offset = (int)disasm.Instruction.AddrValue - buffer.Ptr.ToInt32(); CallOffsets.Add((uint)offset); if (followCalls) { Push(offset+5); // Push the return address on the stack JumpBacks.Add((uint)(disasm.EIP.ToInt32() + 5)); disasm.EIP = new IntPtr((int)disasm.Instruction.AddrValue); return true; } return false; case "cmp": UpdateFlags((ulong)dst.GetValue() - (ulong)src.GetValue(), dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.ParityFlag | EFlags.CarryFlag); break; case "test": ClearFlags(EFlags.OverflowFlag | EFlags.CarryFlag); UpdateFlags(dst.GetValue() & src.GetValue(), dst.Size, EFlags.SignFlag | EFlags.ZeroFlag | EFlags.ParityFlag); break; case "sbb": if (parametersList.Length != 2) break; ulong newValue = (ulong)dst.GetValue() - (ulong)src.GetValue(); if (EFlags.HasFlag(EFlags.CarryFlag)) newValue -= 1; dst.SetValue((uint)newValue); UpdateFlags(newValue, dst.Size, EFlags.OverflowFlag | EFlags.SignFlag | EFlags.ZeroFlag | EFlags.AdjustFlag | EFlags.CarryFlag); break; #region Stack operations case "push": // todo: check for stack overflow (stack pointer < base address) if (parametersList.Length == 1) { uint s = dst.Size; if (s == 2 || s == 4) { WriteMemory(Esp - s, dst.GetValue()); Esp.Value -= s; } } break; case "pop": // todo: check for stack overflow (stack pointer > base address + memory size) if (parametersList.Length == 1 && dst.Type != ArgumentType.Immediate) { uint s = dst.Size; if (s == 2 || s == 4) { dst.SetValue(ReadMemory(Esp, s)); Esp.Value += s; } } break; case "pusha": if (parametersList.Length == 0) { WriteMemory(Esp - 2, Eax.Ax); WriteMemory(Esp - 4, Ecx.Cx); WriteMemory(Esp - 6, Edx.Dx); WriteMemory(Esp - 8, Ebx.Bx); WriteMemory(Esp - 10, Esp.Sp); WriteMemory(Esp - 12, Ebp.Bp); WriteMemory(Esp - 14, Esi.Si); WriteMemory(Esp - 16, Edi.Di); Esp.Value -= 16; } break; case "pushad": if (parametersList.Length == 0) { WriteMemory(Esp - 4, Eax.Value); WriteMemory(Esp - 8, Ecx.Value); WriteMemory(Esp - 12, Edx.Value); WriteMemory(Esp - 16, Ebx.Value); WriteMemory(Esp - 20, Esp.Value); WriteMemory(Esp - 24, Ebp.Value); WriteMemory(Esp - 28, Esi.Value); WriteMemory(Esp - 32, Edi.Value); Esp.Value -= 32; } break; case "popa": if (parametersList.Length == 0) { Edi.Di = ReadWordFromMemory(Esp); Esi.Si = ReadWordFromMemory(Esp + 2); Ebp.Bp = ReadWordFromMemory(Esp + 4); //Esp.Sp = ReadWord(Esp + 6); // ignored Ebx.Bx = ReadWordFromMemory(Esp + 8); Edx.Dx = ReadWordFromMemory(Esp + 10); Ecx.Cx = ReadWordFromMemory(Esp + 12); Eax.Ax = ReadWordFromMemory(Esp + 14); Esp.Value += 16; } else throw new ArgumentException(); break; case "popad": if (parametersList.Length == 0) { Edi.Value = ReadDwordFromMemory(Esp); Esi.Value = ReadDwordFromMemory(Esp + 4); Ebp.Value = ReadDwordFromMemory(Esp + 8); //Esp.Value = ReadDoubleword(Esp + 12); // ignored Ebx.Value = ReadDwordFromMemory(Esp + 16); Edx.Value = ReadDwordFromMemory(Esp + 20); Ecx.Value = ReadDwordFromMemory(Esp + 24); Eax.Value = ReadDwordFromMemory(Esp + 28); Esp.Value += 32; } break; // todo: pushf and popf, and effects on eflags #endregion } } return false; }
public void Execute(uint offset, UnmanagedBuffer buffer, bool followCalls = false) { try { Esp.Value -= 4; // Assume we are calling from the beginning of a function. return address is on the stack Disasm disasm = new Disasm(); disasm.EIP = new IntPtr(buffer.Ptr.ToInt64() + offset); // new IntPtr(buffer.Ptr.ToInt64()/* + offset*/); while (true) { var result = BeaEngine.Disassemble(disasm); if (result == BeaConstants.SpecialInfo.UNKNOWN_OPCODE) return; // Returns true if jumped or following calls var jumped = ExecuteASM(disasm, buffer, followCalls); if ((disasm.CompleteInstr.Contains("leave") || disasm.CompleteInstr.Contains("ret")) && !jumped) break; Debugger.TryTrigger(this, BreakpointType.InstructionName, disasm.Instruction.Mnemonic); if (!jumped) disasm.EIP = new IntPtr(disasm.EIP.ToInt64() + (int)result); } for (var i = 0; i < CallOffsets.Count; ++i) CallOffsets[i] += 0x400C00; } catch (Exception e) { Console.WriteLine(e); } }
public void Execute(int offset, UnmanagedBuffer buffer, bool followCalls = false) { Execute((uint)offset, buffer, followCalls); }
static void Main(string[] args) { Console.WriteLine(">> Loading configuration options..."); if (!Config.Load(args)) { return; } if (Config.NoCmsg && Config.NoSmsg) { Logger.WriteConsoleLine("Please give me something to do."); Config.ShowHelp(); return; } Logger.CreateOutputStream(Config.OutputFile); Console.WriteLine(">> Opening Wow client..."); ClientStream = new BinaryReader(File.OpenRead(Config.Executable)); if (!BaseStream.CanRead) { return; } ClientBytes = File.ReadAllBytes(Config.Executable); Disasm = new UnmanagedBuffer(ClientBytes); Env = Emulator.Create(BaseStream); if (!Config.NoSmsg) { Console.WriteLine(">> Discovering JAM groups..."); foreach (var pattern in ClientGroupPatterns) // Load jam groups... { var offsets = ClientBytes.FindPattern(pattern, 0xFF); if (offsets.Count == 0) { Console.WriteLine(@"Could not find group name "" {0}""", System.Text.Encoding.ASCII.GetString(pattern.Skip(1).ToArray())); return; } else { Console.WriteLine(@"Found JAM Group "" {0}""", System.Text.Encoding.ASCII.GetString(pattern.Skip(1).ToArray())); Dispatchers.Add(new JamDispatch((int)(offsets[0] + 1))); } } } if (!Config.NoGhNames && !Opcodes.TryPopulate()) { return; } if (!Config.NoSmsg) { SMSG.Dump(); } if (!Config.NoCmsg) { CMSG.Dump(Config.SpecificOpcodeValue); } }