Jump to content
Sign in to follow this  
Ben

Club Penguin client tool

Recommended Posts

Hey everyone,

I frequently see people struggling with disableing the domain locking, logging services, and client checks embedded into Club Penguin client files to prevent the files being used outside the http://clubpenguin.com domain.

I have written a tool in Python to help aid the process of disabling these functions, whilst maintaining the crossdomain policies within the files which actually act as a security feature.

import zlib
import logging
import argparse
from os.path import isfile, isdir, splitext, join, exists, dirname
from os import walk, makedirs
from glob import glob

if __name__ == "__main__":
	logger = logging.getLogger(__name__)
	logging.basicConfig(level=logging.INFO)
	parser = argparse.ArgumentParser(description="Club Penguin client tool")
	parser.add_argument("path", type=str, nargs="*", help="Path(s) to files or directories")
	parser.add_argument("-d", "--domain", type=str, help="The domain to use (ex. clubpenguin.com)")
	parser.add_argument("-r", "--recursive", action='store_true', help="Enables recursive mode")
	parser.add_argument("-o", "--output", type=str, help="Output directory")
	parser.add_argument("-D", "--dump", action='store_true', help="Dump decompressed FWS data")
	arguments = parser.parse_args()

	logger.info("This program can overwrite files on the disk, make sure to make backups before" +
				" running this script or make sure the output flag is enabled!")

	for path in arguments.path:
		if isfile(path):
			logger.info("Found \"%s\"", path)
			paths = [path]
		elif isdir(path):
			if not arguments.recursive:
				logger.warning("\"%s\" is a directory but recursion is disabled! skipping...", path)
				continue
			else:
				paths = [y for x in walk(path) for y in glob(join(x[0], '*.swf'))]

		for file in paths:
			logger.info("Found \"%s\"", file)
			filename, file_extension = splitext(file)
			if file_extension != ".swf":
				logger.warning("\"%s\" is not an SWF file! skipping...", path)
				continue

			logger.info("Opening \"%s\"", file)
			raw = open(file, "rb")
			signature = raw.read(3)
			logger.info("Reading file signature for \"%s\"", file)

			if signature != b"CWS":
				logger.warning("File has invalid signature, file sig should be 0x43 0x57 0x43(\"CWS\")")
				continue

			header = raw.read(5)
			data = raw.read()
			logger.info("Read %d bytes from \"%s\"", data.__sizeof__(), file)
			logger.info("Decompressing")
			decompressed_data = zlib.decompress(data)
			original_data = decompressed_data

			if b'\x00clubpenguin\x00boot\x00BootLoader' in decompressed_data:
				logger.info("Found a BootLoader, cracking client checks...")
				s = b'\x00logEvents\x00boot\x00BootL0ader'
				decompressed_data = decompressed_data.replace(b'\x00logEvents\x00boot\x00BootLoader', s)
				s = b'clubpenguin.c0m'
				decompressed_data = decompressed_data.replace(b'clubpenguin.com', s)

			if b'clubpenguin.com' in decompressed_data:
				logger.info("Found clubpenguin.com")
				s = bytes(arguments.domain.encode())
				decompressed_data = decompressed_data.replace(b'clubpenguin.com', s)

			if b'disney.com' in decompressed_data:
				logger.info("Found disney.com")
				s = bytes(arguments.domain.encode())
				decompressed_data = decompressed_data.replace(b'disney.com', s)

			if decompressed_data == original_data:
				logger.warning("No changes were made to the data!")
				continue

			logger.info("Re-compressing data and appending file signature and header")
			compressed = signature + header + zlib.compress(decompressed_data)

			if arguments.output:
				file = join(arguments.output, file)

			if not exists(dirname(file)):
				makedirs(dirname(file), exist_ok=True)

			if arguments.dump:
				dump = open(file + ".fws", "w")
				dump.write(str(decompressed_data))
				dump.close()
				logger.info("Copied dump to \"%s\"", file + ".fws")

			logger.info("Writing data to \"%s\"", file)
			output = open(file, "wb")
			output.write(compressed)
			output.close()
			raw.close()

	logger.info("Finished. Goodbye!")

If you know Python a little then you will probably be able to understand how the script works rather quickly, as it is rather simple. It decompresses the SWF files to expose some of the actionscript constants within the file (no, this script does not make use of SWF disassemblers like RABCasm which makes my script very lightweight and very fast)

The script has a few flags, some of which are just useful, and some of which you'll probably want to use every single time you run it.

$ py iceburg.py -h
usage: iceburg.py [-h] [-d DOMAIN] [-r] [-o OUTPUT] [-D] [path [path ...]]

Club Penguin client tool

positional arguments:
  path                  Path(s) to files or directories

optional arguments:
  -h, --help            show this help message and exit
  -d DOMAIN, --domain DOMAIN
                        The domain to use (ex. clubpenguin.com)
  -r, --recursive       Enables recursive mode
  -o OUTPUT, --output OUTPUT
                        Output directory
  -D, --dump            Dump decompressed FWS data

Domain (required) tells the script which internet domain to replace security locks and logging services with.

Recursive mode will make the script search through every directory below the path you specify for SWF files to check.

Output changes the output directory, assuming the output directory is empty no files will be overwritten.

Dump will make extra files containing the decompressed version of the data, useful for debugging purposes (for example if the script is making changes which break the SWF).

Example usage on real Club Penguin media!

/play/v2/client

  Reveal hidden contents

/play/v2/games/

  Reveal hidden contents

Script download attached :~)

Prerequisites

  • Python 3
  • :)

client-tool.zip

  • Like 5

Share this post


Link to post
Share on other sites

It works fine for /play/v2/client, but when I try it with /play/v2/games, I get the following result:

 INFO:__main__:This program can overwrite files on the disk, make sure to make backups before running this script or make sure the output flag is enabled!
Traceback (most recent call last):
  File "iceburg.py", line 33, in <module>
    for file in paths:
NameError: name 'paths' is not defined

I used this command: python3 iceburg.py -d mydomain.tld -r -D games.

Fixed.

Edited by ReidTJ

Share this post


Link to post
Share on other sites
Sign in to follow this  

×