public static void DumpDescriptors() { foreach (var p in Process.GetProcesses()) { if (p.ProcessName == "Diablo III") { Mem32 m = new Mem32(p); GetMessageOpcodes(m); DumpAttributes(m); XDocument doc = new XDocument(); XElement root = new XElement("TypeDescriptors"); int hash = m[HashAddress].Ptr[HashOffset].Int32; root.Add(new XAttribute("ProtocolHash", hash)); var descriptors = GetAllDescriptors(m); foreach (var desc in descriptors) { root.Add(desc.ToXml()); } doc.Add(root); doc.Save("typedescriptors.xml"); m.Dispose(); DumpOpcodes(descriptors); return; } } Console.WriteLine("Was unable to find any 'Diablo III' process."); }
public static void DumpDescriptors() { foreach (var p in Process.GetProcesses()) { if (p.ProcessName == "Diablo III") { Mem32 m = new Mem32(p); GetMessageOpcodes(m); DumpAttributes(m); XDocument doc = new XDocument(); XElement root = new XElement("TypeDescriptors"); int hash = m[HashAddress].Ptr[HashOffset].Int32; root.Add(new XAttribute("ProtocolHash", hash)); foreach (var desc in GetAllDescriptors(m)) { root.Add(desc.ToXml()); } doc.Add(root); doc.Save("typedescriptors.xml"); m.Dispose(); return; } } Console.WriteLine("Was unable to find any 'Diablo III' process."); }
static void GetMessageOpcodes(Mem32 m) { _gameMessageLookUp = new Dictionary <int, GameMessageInfo>(); var func = m[OpcodeSwitch_Address]; int maxOpcode = func[0x1B].Int32 + 1; int jaOffset = func[0x21].Int32; int defaultCase = func.Offset + 0x25 + jaOffset; var switchTable = func[0x28].Ptr; for (int i = 0; i < maxOpcode; i++) { int caseOffset = switchTable[i * 4].Int32; if (caseOffset == defaultCase) { continue; } int offTypeDescriptor = m[caseOffset + 2].Ptr.Int32; int size = m[caseOffset + 13].Int32; int opcode = i + 1; GameMessageInfo gmi; if (_gameMessageLookUp.TryGetValue(offTypeDescriptor, out gmi)) { if (gmi.Size != size) { throw new Exception("Size mismatch."); } } else { gmi = new GameMessageInfo(); gmi.Offset = offTypeDescriptor; gmi.Size = size; _gameMessageLookUp.Add(offTypeDescriptor, gmi); } gmi.Opcodes.Add(opcode); } }
static void GetMessageOpcodes(Mem32 m) { _gameMessageLookUp = new Dictionary<int, GameMessageInfo>(); var func = m[OpcodeSwitch_Address]; int maxOpcode = func[0x1B].Int32 + 1; int jaOffset = func[0x21].Int32; int defaultCase = func.Offset + 0x25 + jaOffset; var switchTable = func[0x28].Ptr; for (int i = 0; i < maxOpcode; i++) { int caseOffset = switchTable[i * 4].Int32; if (caseOffset == defaultCase) continue; int offTypeDescriptor = m[caseOffset + 2].Ptr.Int32; int size = m[caseOffset + 13].Int32; int opcode = i + 1; GameMessageInfo gmi; if (_gameMessageLookUp.TryGetValue(offTypeDescriptor, out gmi)) { if (gmi.Size != size) throw new Exception("Size mismatch."); } else { gmi = new GameMessageInfo(); gmi.Offset = offTypeDescriptor; gmi.Size = size; _gameMessageLookUp.Add(offTypeDescriptor, gmi); } gmi.Opcodes.Add(opcode); } }
static TypeDescriptor[] GetAllDescriptors(Mem32 mem) { Dictionary <int, TypeDescriptor> table = new Dictionary <int, TypeDescriptor>(); var link = mem[TypeDescriptorsAddress].Ptr; int count = 0; while (link.Int32 != 0) { if (table.ContainsKey(link.Offset) == false) { var desc = DiscoverMessageDescriptors(mem, table, link.Offset); } count++; link = link[TypeDescriptorsOffset].Ptr; } var result = table.Values.ToArray(); for (int i = 0; i < result.Length; i++) { result[i].Index = i; } return(result); }
static void DumpAttributes(Mem32 mem) { // could get the max num from descriptor var attribList = mem[AttributesAddress]; NetAttribute.Attributes = new NetAttribute[AttributeCount]; for (int i = 0; i < AttributeCount; i++) { var attrib = attribList[i * 40]; int id = attrib.Int32; int u2 = attrib[4].Int32; int u3 = attrib[8].Int32; int u4 = attrib[12].Int32; int u5 = attrib[16].Int32; string scriptA = attrib[20].CStringPtr; string scriptB = attrib[24].CStringPtr; string name = attrib[28].CStringPtr; var decoder = attrib[32].Ptr; byte u10 = attrib[36].Byte; switch (decoder.Int32) { case Attribute_Int: { int bitCount = decoder[12].Int32; NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.Int, u10, 0, 0, bitCount); break; } case Attribute_IntMinMax: { int bitCount = decoder[20].Int32; int min = decoder[12].Int32; int max = decoder[16].Int32; NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.IntMinMax, u10, min, max, bitCount); break; } case Attribute_Float16: // Decode16BitFloat(bits) { int bitCount = decoder[12].Int32; NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.Float16, u10, 0, 0, bitCount); } break; case Attribute_Float16Or32: { NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.Float16Or32, u10, 0, 0, 0); } break; case Attribute_FloatMinMax: // DecodeFloatMinMax throw new Exception("FloatMinMax used"); default: throw new Exception("Unknown decoder used"); } } NetAttribute.SaveXml("attributes.xml"); }
static TypeDescriptor[] GetAllDescriptors(Mem32 mem) { Dictionary<int, TypeDescriptor> table = new Dictionary<int, TypeDescriptor>(); var link = mem[TypeDescriptorsAddress].Ptr; int count = 0; while (link.Int32 != 0) { if (table.ContainsKey(link.Offset) == false) { var desc = DiscoverMessageDescriptors(mem, table, link.Offset); } count++; link = link[TypeDescriptorsOffset].Ptr; } var result = table.Values.ToArray(); for (int i = 0; i < result.Length; i++) result[i].Index = i; return result; }
static TypeDescriptor DiscoverMessageDescriptors(Mem32 mem, Dictionary<int, TypeDescriptor> table, int offset) { if (offset == 0) return null; string name = mem[offset + 4].CStringPtr; int unkValue = mem[offset + 8].Int32; var fields = mem[offset + 12].Ptr; if (fields.Offset == 0) { var basicType = TypeDescriptor.AllocateBasicType(name); basicType.Name = name; basicType.UnkValue = unkValue; table.Add(offset, basicType); return basicType; } StructureTypeDescriptor typeDesc; GameMessageInfo gmi; if (_gameMessageLookUp.TryGetValue(offset, out gmi)) { var gm = TypeDescriptor.AllocateGameMessage(name); gm.Size = gmi.Size; gm.NetworkIds = gmi.Opcodes.ToArray(); typeDesc = gm; } else typeDesc = TypeDescriptor.AllocateStructure(name); typeDesc.Name = name; typeDesc.UnkValue = unkValue; table.Add(offset, typeDesc); List<FieldDescriptor> list = new List<FieldDescriptor>(); for (; ; ) { FieldDescriptor f = new FieldDescriptor(); f.Name = fields.CStringPtr; int type = fields[4].Int32; if (mem[type + 4].CStringPtr != "DT_NULL" && !table.TryGetValue(type, out f.Type)) f.Type = DiscoverMessageDescriptors(mem, table, type); f.Offset = fields[8].Int32; var defaultValuePtr = fields[12].Ptr; f.Min = fields[0x10].Int32; f.Max = fields[0x14].Int32; f.Flags = fields[0x18].Int32; type = fields[0x1C].Int32; if (mem[type + 4].CStringPtr != "DT_NULL" && !table.TryGetValue(type, out f.SubType)) f.SubType = DiscoverMessageDescriptors(mem, table, type); f.VariableOffset = fields[0x20].Int32; f.ArrayLength = fields[0x24].Int32; f.ArrayLengthOffset = fields[0x28].Int32; f.EncodedBits = fields[0x2C].UInt16; f.EncodedBits2 = fields[0x2E].UInt16; f.SnoType = fields[0x30].Int32; f.TagMapRelated = fields[0x34].Int32; var enumFields = fields[0x38].Ptr; if (enumFields.Offset != 0) { List<Tuple<string, int>> enums = new List<Tuple<string, int>>(); for (; ; ) { if (enumFields[4].Int32 == 0) break; enums.Add(new Tuple<string, int>(enumFields[4].CStringPtr, enumFields.Int32)); enumFields = enumFields[8]; } f.EnumFields = enums.ToArray(); } f.FlagIndex = fields[0x3C].Int32; int funcA = fields[0x40].Int32; // TODO int funcB = fields[0x44].Int32; // TODO f.DspIndex = fields[0x48].Int32; var str = fields[0x4C].CString; // 0x4C 64 bytes, unused string //if (str != string.Empty) Console.WriteLine(str); list.Add(f); if (fields.Int32 == 0) break; fields = fields[140]; } typeDesc.Fields = list.ToArray(); return typeDesc; }
public MemAddress32(Mem32 mem, int offset) { Memory = mem; Offset = offset; }
static void DumpAttributes(Mem32 mem) { // could get the max num from descriptor var attribList = mem[AttributesAddress]; NetAttribute.Attributes = new NetAttribute[AttributeCount]; for (int i = 0; i < AttributeCount; i++) { var attrib = attribList[i * 40]; int id = attrib.Int32; int u2 = attrib[4].Int32; int u3 = attrib[8].Int32; int u4 = attrib[12].Int32; int u5 = attrib[16].Int32; string scriptA = attrib[20].CStringPtr; string scriptB = attrib[24].CStringPtr; string name = attrib[28].CStringPtr; var decoder = attrib[32].Ptr; byte u10 = attrib[36].Byte; switch (decoder.Int32) { case Attribute_Int: { int bitCount = decoder[12].Int32; NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.Int, u10, 0, 0, bitCount); break; } case Attribute_IntMinMax: { int bitCount = decoder[20].Int32; int min = decoder[12].Int32; int max = decoder[16].Int32; NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.IntMinMax, u10, min, max, bitCount); break; } case Attribute_Float16: // Decode16BitFloat(bits) { int bitCount = decoder[12].Int32; NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.Float16, u10, 0, 0, bitCount); } break; case Attribute_Float16Or32: { NetAttribute.Attributes[id] = new NetAttribute(id, u2, u3, u4, u5, scriptA, scriptB, name, NetAttributeEncoding.Float16Or32, u10, 0, 0, 0); } break; case Attribute_FloatMinMax: // DecodeFloatMinMax throw new Exception("FloatMinMax used"); default: throw new Exception("Unknown decoder used"); } } NetAttribute.SaveXml("attributes.xml"); }
static TypeDescriptor DiscoverMessageDescriptors(Mem32 mem, Dictionary <int, TypeDescriptor> table, int offset) { if (offset == 0) { return(null); } string name = mem[offset + 4].CStringPtr; int unkValue = mem[offset + 8].Int32; var fields = mem[offset + 12].Ptr; if (fields.Offset == 0) { var basicType = TypeDescriptor.AllocateBasicType(name); basicType.Name = name; basicType.UnkValue = unkValue; table.Add(offset, basicType); return(basicType); } StructureTypeDescriptor typeDesc; GameMessageInfo gmi; if (_gameMessageLookUp.TryGetValue(offset, out gmi)) { var gm = TypeDescriptor.AllocateGameMessage(name); gm.Size = gmi.Size; gm.NetworkIds = gmi.Opcodes.ToArray(); typeDesc = gm; } else { typeDesc = TypeDescriptor.AllocateStructure(name); } typeDesc.Name = name; typeDesc.UnkValue = unkValue; table.Add(offset, typeDesc); List <FieldDescriptor> list = new List <FieldDescriptor>(); for (; ;) { FieldDescriptor f = new FieldDescriptor(); f.Name = fields.CStringPtr; int type = fields[4].Int32; if (mem[type + 4].CStringPtr != "DT_NULL" && !table.TryGetValue(type, out f.Type)) { f.Type = DiscoverMessageDescriptors(mem, table, type); } f.Offset = fields[8].Int32; var defaultValuePtr = fields[12].Ptr; f.Min = fields[0x10].Int32; f.Max = fields[0x14].Int32; f.Flags = fields[0x18].Int32; type = fields[0x1C].Int32; if (mem[type + 4].CStringPtr != "DT_NULL" && !table.TryGetValue(type, out f.SubType)) { f.SubType = DiscoverMessageDescriptors(mem, table, type); } f.VariableOffset = fields[0x20].Int32; f.ArrayLength = fields[0x24].Int32; f.ArrayLengthOffset = fields[0x28].Int32; f.EncodedBits = fields[0x2C].UInt16; f.EncodedBits2 = fields[0x2E].UInt16; f.SnoType = fields[0x30].Int32; f.TagMapRelated = fields[0x34].Int32; var enumFields = fields[0x38].Ptr; if (enumFields.Offset != 0) { List <Tuple <string, int> > enums = new List <Tuple <string, int> >(); for (; ;) { if (enumFields[4].Int32 == 0) { break; } enums.Add(new Tuple <string, int>(enumFields[4].CStringPtr, enumFields.Int32)); enumFields = enumFields[8]; } f.EnumFields = enums.ToArray(); } f.FlagIndex = fields[0x3C].Int32; int funcA = fields[0x40].Int32; // TODO int funcB = fields[0x44].Int32; // TODO f.DspIndex = fields[0x48].Int32; var str = fields[0x4C].CString; // 0x4C 64 bytes, unused string //if (str != string.Empty) Console.WriteLine(str); list.Add(f); if (fields.Int32 == 0) { break; } fields = fields[140]; } typeDesc.Fields = list.ToArray(); return(typeDesc); }
public MemAddress32(Mem32 mem, int offset) { Memory = mem; Offset = offset; }