private static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += UnhandledException; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Settings = LoadSettings(); if (args.Length > 0 && args[0].EndsWith(".swf")) { var clientInfo = new FileInfo(Path.GetFullPath(args[0])); using (var game = new HGame(clientInfo.FullName)) { game.Disassemble(); game.DisableHostChecks(); game.InjectKeyShouter(4001); game.InjectEndPointShouter(4000); game.InjectEndPoint("127.0.0.1", (int)Settings["ConnectionListenPort"]); string moddedClientPath = Path.Combine(clientInfo.DirectoryName, "MOD_" + clientInfo.Name); using (var fileOutput = File.Open(moddedClientPath, FileMode.Create)) using (var output = new FlashWriter(fileOutput)) { game.Assemble(output, CompressionKind.ZLIB); } MessageBox.Show($"File has been modified/re-assembled successfully at '{moddedClientPath}'.", "Tanji - Alert!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); } return; } Eavesdropper.Certifier = new CertificateManager("Tanji", "Tanji Certificate Authority"); Eavesdropper.Overrides.AddRange(((string)Settings["ProxyOverrides"]).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)); Application.Run(new MainFrm()); }
public static Task <HGame> GetGameAsync(string revision) { return(ReadContentAsync(HHotel.Com.ToUri("images"), $"/gordon/{revision}/Habbo.swf", async content => { var game = new HGame(await content.ReadAsStreamAsync().ConfigureAwait(false)); game.Disassemble(); return game; })); }
private Task InjectGameClientAsync(object sender, RequestInterceptedEventArgs e) { if (!e.Uri.Query.StartsWith("?" + _randomQuery)) { return(Task.CompletedTask); } Eavesdropper.RequestInterceptedAsync -= InjectGameClientAsync; Uri remoteUrl = e.Request.RequestUri; string clientPath = Path.Combine(Master.DataDirectory.FullName, $@"Modified Clients\{remoteUrl.Host}\{remoteUrl.LocalPath}"); if (!File.Exists(clientPath)) { _ui.SetStatusMessage(Constants.INTERCEPTING_CLIENT); Eavesdropper.ResponseInterceptedAsync += InterceptGameClientAsync; } else { _ui.SetStatusMessage(Constants.DISASSEMBLING_CLIENT); using var game = new HGame(clientPath); game.Disassemble(); _ui.SetStatusMessage(Constants.GENERATING_MESSAGE_HASHES); game.GenerateMessageHashes(Path.Combine(Master.ProgramDirectory.FullName, "Hashes.ini")); //We don't need this stuff in HabboGallery foreach (HMessage message in game.Out.Concat(game.In)) { message.Class = null; message.Parser = null; message.Structure = null; message.References.Clear(); } Master.In = game.In; Master.Out = game.Out; Task interceptConnectionTask = InterceptConnectionAsync(); e.Request = WebRequest.Create(new Uri(clientPath)); TerminateProxy(); } return(Task.CompletedTask); }
private static void PatchClient(FileInfo clientInfo) { using (var game = new HGame(clientInfo.FullName)) { game.Disassemble(); game.DisableHostChecks(); game.InjectKeyShouter(4001); game.InjectEndPointShouter(4000); game.InjectEndPoint("127.0.0.1", (int)Settings["ConnectionListenPort"]); string moddedClientPath = Path.Combine(clientInfo.DirectoryName, "MOD_" + clientInfo.Name); using (var fileOutput = File.Open(moddedClientPath, FileMode.Create)) using (var output = new FlashWriter(fileOutput)) { game.Assemble(output, CompressionKind.ZLIB); } MessageBox.Show($"File has been modified/re-assembled successfully at '{moddedClientPath}'.", "Tanji - Alert!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); } }
private async Task ReceiveRemoteContractorDataAsync() { try { HMessage packet = await _remoteContractor.ReceivePacketAsync().ConfigureAwait(false); if (packet == null) { Environment.Exit(0); } #region Switch: packet.Header switch (packet.Header) { case 0: { _initStep++; _hotel = (HHotel)packet.ReadShort(); break; } case 1: { _initStep++; _in = new Incoming(); _out = new Outgoing(); string location = packet.ReadString(); if (!string.IsNullOrWhiteSpace(location)) { _game = new HGame(location); _game.Disassemble(); _game.GenerateMessageHashes(); if (packet.Readable > 0) { string hashesPath = packet.ReadString(); _in.Load(_game, hashesPath); _out.Load(_game, hashesPath); } _module.ModifyGame(_game); } break; } case 2: { _initStep++; _gameData = new HGameData(packet.ReadString()); _module.ModifyGameData(_gameData); break; } case 3: { _initStep++; var connection = (ContractorProxy)_connection; connection.Port = packet.ReadShort(); connection.Host = packet.ReadString(); connection.Address = packet.ReadString(); break; } case 4: case 5: { var destination = (HDestination)(packet.Header - 4); string stamp = packet.ReadString(); int step = packet.ReadInteger(); bool isBlocked = packet.ReadBoolean(); int dataLength = packet.ReadInteger(); byte[] data = packet.ReadBytes(dataLength); var interPacket = new HMessage(data, destination); var args = new DataInterceptedEventArgs(interPacket, step, (destination == HDestination.Server)); try { if (destination == HDestination.Server) { _module.HandleOutgoing(args); } else { _module.HandleIncoming(args); } } finally { await SendInterceptedDataResponseAsync( stamp, args).ConfigureAwait(false); } break; } } #endregion if (_initStep == 4) { _initializationSource?.SetResult(true); } } finally { Task receiveRemContDataTask = ReceiveRemoteContractorDataAsync(); } }
private void Compare(string[] args) { using (var game_1 = new HGame(args[0])) using (var game_2 = new HGame(args[1])) { game_1.Disassemble(); game_2.Disassemble(); var matchedHashes = new List <string>(); var oldUnmatched = new Dictionary <string, List <ASMethod> >(); var unmatchedMethods = new Dictionary <string, List <ASMethod> >(); foreach (ASMethod method in game_1.ABCFiles[0].Methods) { using (var hasher = new HashWriter(false)) { hasher.Write(method); string hash = hasher.GenerateMD5Hash(); List <ASMethod> methods = null; if (!unmatchedMethods.TryGetValue(hash, out methods)) { methods = new List <ASMethod>(); unmatchedMethods.Add(hash, methods); } methods.Add(method); } } foreach (ASMethod method in game_2.ABCFiles[0].Methods) { using (var hasher = new HashWriter(false)) { hasher.Write(method); string hash = hasher.GenerateMD5Hash(); if (unmatchedMethods.ContainsKey(hash)) { matchedHashes.Add(hash); unmatchedMethods.Remove(hash); } else if (!matchedHashes.Contains(hash)) { List <ASMethod> methods = null; if (!oldUnmatched.TryGetValue(hash, out methods)) { methods = new List <ASMethod>(); oldUnmatched.Add(hash, methods); } methods.Add(method); } } } var changes = string.Empty; foreach (string hash in unmatchedMethods.Keys) { changes += $"[{hash}]\r\n{{\r\n"; foreach (ASMethod method in unmatchedMethods[hash]) { changes += $" {(method.Container?.QName.Name ?? "Anonymous")}\r\n"; changes += $" {method.ToAS3()}\r\n\r\n"; } changes += $"}}\r\n"; } } }
private void Extract() { if (Options.DumpInfo != null || Options.MatchInfo != null) { Console.Write("Generating Message Hashes..."); Game.GenerateMessageHashes(); ConsoleEx.WriteLineFinished(); string hashesPath = (_baseDirectory + "Hashes.ini"); In.Load(Game, hashesPath); Out.Load(Game, hashesPath); } if (Options.DumpInfo != null) { string msgsPath = Path.Combine(Options.OutputDirectory, "Messages.txt"); using (var msgsOutput = new StreamWriter(msgsPath, false)) { msgsOutput.WriteLine("// " + Game.Revision); msgsOutput.WriteLine(); msgsOutput.WriteLine("// Outgoing Messages | " + Game.OutMessages.Count.ToString("n0")); WriteMessages(msgsOutput, "Outgoing", Game.OutMessages); msgsOutput.WriteLine(); msgsOutput.WriteLine("// Incoming Messages | " + Game.InMessages.Count.ToString("n0")); WriteMessages(msgsOutput, "Incoming", Game.InMessages); Console.WriteLine("Messages Saved: " + msgsPath); } string identitiesPath = Path.Combine(Options.OutputDirectory, "Identities.ini"); using (var output = new StreamWriter(identitiesPath)) { output.WriteLine(Game.Revision); Out.Save(output); output.WriteLine(); In.Save(output); } if (Options.DumpInfo.IsDumpingImages) { var imgDirectory = Directory.CreateDirectory(Options.OutputDirectory + "\\ImageFiles"); foreach (DefineBitsLossless2Tag bitsTag in Game.Tags .Where(t => t.Kind == TagKind.DefineBitsLossless2)) { string imgPath = Path.Combine(imgDirectory.FullName, "img_" + bitsTag.Id + ".png"); Color[,] table = bitsTag.GetARGBMap(); int width = table.GetLength(0); int height = table.GetLength(1); using (var asset = new Image <Rgba32>(width, height)) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Color pixel = table[x, y]; asset[x, y] = new Rgba32(pixel.R, pixel.G, pixel.B, pixel.A); } } using (var output = new StreamWriter(imgPath)) { asset.SaveAsPng(output.BaseStream); } } } } if (Options.DumpInfo.IsDumpingBinaryData) { var binDirectory = Directory.CreateDirectory(Options.OutputDirectory + "\\BinaryDataFiles"); foreach (DefineBinaryDataTag binTag in Game.Tags .Where(t => t.Kind == TagKind.DefineBinaryData)) { string binPath = Path.Combine(binDirectory.FullName, "bin_" + binTag.Id + ".xml"); if (Options.DumpInfo.IsMergingBinaryData) { using (var binOutput = File.Open(Options.OutputDirectory + "\\binaryData.xml", FileMode.Append, FileAccess.Write)) { binOutput.Write(binTag.Data, 0, binTag.Data.Length); } } else { File.WriteAllBytes(binPath, binTag.Data); } } } if (Options.MatchInfo != null) { MatchCommand matchInfo = Options.MatchInfo; using (var previousGame = new HGame(matchInfo.PreviousGameInfo.FullName)) { Console.Write("Preparing Hash Comparison..."); previousGame.Disassemble(); previousGame.GenerateMessageHashes(); ConsoleEx.WriteLineFinished(); Console.Write("Matching Outgoing Messages..."); ReplaceHeaders(matchInfo.ClientHeadersInfo, previousGame.OutMessages, previousGame.Revision); ConsoleEx.WriteLineFinished(); Console.Write("Matching Incoming Messages..."); ReplaceHeaders(matchInfo.ServerHeadersInfo, previousGame.InMessages, previousGame.Revision); ConsoleEx.WriteLineFinished(); } } } }
static async Task GenerateResults(string[] args) { var hotels = new string[] { ".com", ".fr", ".com.tr", ".nl", ".de", ".it", ".fi", ".es", ".com.br" }; var files = new List <string>(); files = args.ToList(); var incomingHashesWithNames = LoadHashesWithName("Incoming"); var outgoingHashesWithNames = LoadHashesWithName("Outgoing"); foreach (var file in files) { var swfBytes = await File.ReadAllBytesAsync(file); Console.WriteLine($"[Updater] Fetched {file}, Size: {swfBytes.Length / 1024}mb"); var game = new HGame(swfBytes); Console.WriteLine($"[Updater] Disassembling SWF"); game.Disassemble(); game.GenerateMessageHashes(); Console.WriteLine($"[Updater] Incoming messages: {game.In.Count}"); Console.WriteLine($"[Updater] Outgoing messages: {game.Out.Count}"); var revisionInfo = new RevisionInfo() { Tag = game.Revision, FirstSeen = DateTime.UtcNow }; foreach (var message in game.In) { string name = null; if (incomingHashesWithNames.ContainsKey(message.Hash)) { name = incomingHashesWithNames[message.Hash]; } revisionInfo.IncomingMessages.Add(message.Id, new MessageInfo() { Hash = message.Hash, Name = name, Structure = message.Structure, ClassName = message.ClassName, ClassNamespace = message.Class.QName.Namespace.Name, References = message.References.Count, ParserName = message.ParserName, ParserNamespace = message.Parser.QName.Namespace.Name }); } foreach (var message in game.Out) { string name = null; if (outgoingHashesWithNames.ContainsKey(message.Hash)) { name = outgoingHashesWithNames[message.Hash]; } revisionInfo.OutgoingMessages.Add(message.Id, new MessageInfo() { Hash = message.Hash, Name = name, Structure = message.Structure, ClassName = message.ClassName, ClassNamespace = message.Class.QName.Namespace.Name, References = message.References.Count }); } revisionInfo.IncomingMessages.ToList().ForEach(x => insertSQL(game.Revision, "In", x.Key, x.Value)); revisionInfo.OutgoingMessages.ToList().ForEach(x => insertSQL(game.Revision, "Out", x.Key, x.Value)); string json = JsonConvert.SerializeObject(revisionInfo); File.WriteAllText($"{basedir}/revisions/{game.Revision}.json", json); } }
private async Task InterceptGameClientAsync(object sender, ResponseInterceptedEventArgs e) { if (e.ContentType != "application/x-shockwave-flash") { return; } if (!e.Uri.Query.StartsWith("?" + _randomQuery)) { return; } Eavesdropper.ResponseInterceptedAsync -= InterceptGameClientAsync; string clientPath = Path.Combine(Master.DataDirectory.FullName, $@"Modified Clients\{e.Uri.Host}\{e.Uri.LocalPath}");; string clientDirectory = Path.GetDirectoryName(clientPath); Directory.CreateDirectory(clientDirectory); _ui.SetStatusMessage(Constants.DISASSEMBLING_CLIENT); using var game = new HGame(await e.Content.ReadAsStreamAsync().ConfigureAwait(false)) { Location = clientPath }; game.Disassemble(); _ui.SetStatusMessage(Constants.GENERATING_MESSAGE_HASHES); game.GenerateMessageHashes(Path.Combine(Master.ProgramDirectory.FullName, "Hashes.ini")); //We don't need this stuff in HabboGallery foreach (HMessage message in game.Out.Concat(game.In)) { message.Class = null; message.Parser = null; message.Structure = null; message.References.Clear(); } Master.In = game.In; Master.Out = game.Out; _ui.SetStatusMessage(Constants.MODIFYING_CLIENT); game.DisableHostChecks(); game.InjectKeyShouter(4001); game.InjectEndPointShouter(4000); game.InjectEndPoint("127.0.0.1", Connection.ListenPort); CompressionKind compression = CompressionKind.ZLIB; #if DEBUG compression = CompressionKind.None; #endif _ui.SetStatusMessage(Constants.ASSEMBLING_CLIENT); byte[] payload = game.ToArray(compression); e.Headers[HttpResponseHeader.ContentLength] = payload.Length.ToString(); e.Content = new ByteArrayContent(payload); using (FileStream clientStream = File.Open(clientPath, FileMode.Create, FileAccess.Write)) { clientStream.Write(payload); } TerminateProxy(); Task interceptConnectionTask = InterceptConnectionAsync(); }
static async Task GenerateResults() { var hotels = new string[] { ".com", ".fr", ".com.tr", ".nl", ".de", ".it", ".fi", ".es", ".com.br" }; var revisions = new List <string>(); Console.WriteLine($"[Updater] Checking revisions for hotels: [{string.Join(", ", hotels)}]"); var history = new List <HistoryInfo>(); foreach (var hotel in hotels) { var variables = await GetVariablesAsync(hotel); var client_url = GetClientUrl(variables); var revision = new Regex("(PRODUCTION\\-\\d+\\-\\d+)").Match(client_url).Groups[1].Value; Console.WriteLine($"[Updater] Habbo{hotel} : {revision}"); if (!revisions.Contains(revision)) { revisions.Add(revision); } history.Add(new HistoryInfo() { Hotel = hotel, Revision = revision, LastChecked = DateTime.UtcNow }); } File.WriteAllText("/var/www/sites/api.harble.net/last.json", JsonConvert.SerializeObject(history)); var incomingHashesWithNames = LoadHashesWithName("Incoming"); var outgoingHashesWithNames = LoadHashesWithName("Outgoing"); foreach (var revision in revisions) { if (File.Exists($"/var/www/sites/api.harble.net/revisions/{revision}.json")) { Console.WriteLine($"[Updater] Already fetched {revision}"); continue; } var swfBytes = await GetClientSwfAsync(revision); Console.WriteLine($"[Updater] Fetched {revision}, Size: {swfBytes.Length / 1024}mb"); var game = new HGame(swfBytes); Console.WriteLine($"[Updater] Disassembling SWF"); game.Disassemble(); game.GenerateMessageHashes(); Console.WriteLine($"[Updater] Incoming messages: {game.InMessages.Count}"); Console.WriteLine($"[Updater] Outgoing messages: {game.OutMessages.Count}"); var revisionInfo = new RevisionInfo() { Tag = revision, FirstSeen = DateTime.UtcNow }; foreach (var message in game.InMessages) { string name = null; if (incomingHashesWithNames.ContainsKey(message.Value.Hash)) { name = incomingHashesWithNames[message.Value.Hash]; } revisionInfo.IncomingMessages.Add(message.Key, new MessageInfo() { Hash = message.Value.Hash, Name = name }); } foreach (var message in game.OutMessages) { string name = null; if (outgoingHashesWithNames.ContainsKey(message.Value.Hash)) { name = outgoingHashesWithNames[message.Value.Hash]; } revisionInfo.OutgoingMessages.Add(message.Key, new MessageInfo() { Hash = message.Value.Hash, Name = name }); } string json = JsonConvert.SerializeObject(revisionInfo); File.WriteAllText($"/var/www/sites/api.harble.net/revisions/{revision}.json", json); } }