Release v1.1.1

This commit is contained in:
hyugogirubato 2024-10-05 14:25:44 +02:00
parent 2866913c05
commit cc56a52b88
7 changed files with 2340 additions and 1843 deletions

View File

@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.1.1] - 2024-10-05
### Added
- Option to export the KID and key based on the service in the server settings.
- Introduced a rule to monitor and manage the usage count for users with free tickets.
- Rule to keep track of updates for users with free tickets.
- Rule to disable the evolution of the license, preventing unwanted advertisements.
- New server specifically designed to bypass trial limitations for DRM services.
### Changed
- Enhanced the documentation for better clarity and usability.
- New method for bypassing restrictions using the KID.
### Fixed
- Fixed issues in the trial disc patch.
- Resolved issues with the expiration date display for `LIFETIME` tickets.
## [1.1.0] - 2024-09-29
### Added
@ -54,7 +74,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Initial release of the project, laying the foundation for future enhancements and features.
[1.1.0]: https://cdm-project.com/hyugogirubato/DVDFabLifetimeActivation
[1.0.2]: https://cdm-project.com/hyugogirubato/DVDFabLifetimeActivation
[1.0.1]: https://cdm-project.com/hyugogirubato/DVDFabLifetimeActivation
[1.0.0]: https://cdm-project.com/hyugogirubato/DVDFabLifetimeActivation
[1.1.1]: https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense/releases/tag/v1.1.1
[1.1.0]: https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense/releases/tag/v1.1.0
[1.0.2]: https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense/releases/tag/v1.0.2
[1.0.1]: https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense/releases/tag/v1.0.1
[1.0.0]: https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense/releases/tag/v1.0.0

113
README.md
View File

@ -1,47 +1,49 @@
# DVDFab: Extended License
This tool provides advanced license management and ticketing capabilities for DVDFab software, bypassing limitations and enabling unrestricted access to all available features.
The **DVDFab Extended License** is designed to manage licenses for DVDFab software effectively. It offers advanced features that enable unrestricted access to all DVDFab products while ensuring user privacy and security.
## Features
The DVDFab Extended License tool offers a wide range of features, including:
- 🔒 **Analytics Deactivation:** Disables all data collection and analytics within DVDFab to protect user privacy.
- 🔓 **Unlock All Products & Features:** Provides access to every product and feature available within the DVDFab suite without limitations.
- 💻 **Cross-Platform Support:** Works across multiple operating systems, including Windows, macOS, and Android (with appropriate configurations).
- 🛠️ **Custom Ticket Generation:** Create fully customized tickets with various licensing options such as "Lifetime," "Subscriber," "Free," or "No Login."
- 🌐 **Mocking Server Support:** Integrates with HTTP interception tools to patch requests and bypass server-side verification.
- 🔒 **Analytics Deactivation**: Completely disable data collection and analytics in DVDFab to protect user privacy.
- 🔓 **Unlock All Products & Features**: Gain unrestricted access to every product and feature available within the DVDFab suite.
- 💻 **Cross-Platform Support**: Compatible with multiple operating systems, including Windows, macOS, and Android.
- 🛠️ **Custom Ticket Generation**: Generate fully customized tickets with various licensing options, including "Lifetime," "Subscriber," "Free," or "No Login."
- 🌐 **Mocking Server Support**: Integrate with HTTP interception tools to modify requests and bypass server-side verification for enhanced functionality.
## Prerequisites
You'll need **HTTP Toolkit (Pro)** to intercept and modify network traffic. Download it from the [HTTP Toolkit Website](https://httptoolkit.com/).
To use this tool, you will need **HTTP Toolkit (Pro)** for intercepting and modifying network traffic. You can download it from the [HTTP Toolkit Website](https://httptoolkit.com/).
## Installation
1. **Clone the Repository**
Open your terminal and run the following commands:
```bash
git clone https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense.git
cd dvdfabextendedlicense
```
### Step 1: Clone the Repository
2. **Install Python Dependencies**
Run the following command to install the required packages:
```bash
pip install -r requirements.txt
```
Open your terminal and run the following commands:
```bash
git clone https://cdm-project.com/hyugogirubato/DVDFabExtendedLicense
```
### Step 2: Install Python Dependencies
Install the required packages by running:
```bash
pip install -r requirements.txt
```
## Usage
### 1. Import Certificates
In the **HTTP Toolkit** settings, you need to import the `.crt` certificates located in the `docs` folder to intercept the network traffic of applications.
Import the `.crt` certificates located in the `docs` folder into the **HTTP Toolkit** settings to enable interception of the application's network traffic.
<img src="./docs/images/import_ca.png" width="60%">
### 2. Generate Custom Mock Rules
You will need to generate mock rules to be used in **HTTP Toolkit** for intercepting and modifying network traffic.
Create mock rules to be used with **HTTP Toolkit** for intercepting and modifying network traffic.
Run the following command:
```bash
@ -55,20 +57,32 @@ python rules.py --rules template.json --output my_rules.json
After generating the rules, import the resulting file into HTTP Toolkit.
### 3. Bypass License Authentication
### 3. Run the Mock Server
After generating the ticket, enable the **Bypass Auth Ticket** rule in HTTP Toolkit. Then, launch the DVDFab software through an intercepted terminal and log in with your credentials.
> [!WARNING]
> This step is required for applications that process DRM content but optional for others.
Once logged in, close the software, enable the **Bypass Auth Ticket** rule, and relaunch the software.
Before launching any DVDFab product with the mock rules, ensure the server is running.
To run the server:
```bash
python server.py --export
```
### 4. Bypass License Authentication
After generating custom mock rules, import them into **HTTP Toolkit**. Launch the DVDFab software through an intercepted terminal and log in with your credentials. After logging in, close the software and enable the **Bypass Auth Ticket** rule to activate the software.
<img src="./docs/images/mock_rules.png" width="60%">
### 4. Advanced License Management
### 5. Advanced License Management
> [!NOTE]
> By default, the generated ticket corresponds to a Fab365 ticket. However, this module allows users to generate other ticket formats based on their preferences.
This tool provides multiple ways to manage tickets, including logging in, using an existing token, or extracting information from old tickets.
<img src="./docs/images/mock_requests.png" width="60%">
<img src="./docs/images/ticket_info.png" width="80%">
#### Command Options for Ticket Management
@ -78,55 +92,44 @@ usage: ticket.py [-h] [--type {SUBSCRIBER,LIFETIME,FREE,NO_LOGIN}]
{login,token,ticket,info} ...
```
**Positional Arguments:**
**Positional Arguments**:
- `login` Log in using account credentials.
- `token` Use an existing user token.
- `ticket` Use a pre-existing ticket string.
- `info` Extract ticket information from a serialized ticket string.
**Optional Arguments:**
- `--type` Ticket type, options: `SUBSCRIBER`, `LIFETIME`, `FREE`, `NO_LOGIN`.
**Optional Arguments**:
- `--type` Ticket type options: `SUBSCRIBER`, `LIFETIME`, `FREE`, `NO_LOGIN`.
- `--version` Specify software version (default: 6200).
- `--expire` Number of days until the ticket expires (default: 365 days).
- `--expire` Specify the number of days until the ticket expires (default: 365 days).
#### Example Ticket Generation
1. **Log in and Generate Ticket:**
1. **Log in and Generate a Ticket**:
```bash
python ticket.py login myemail@example.com mypassword --client WINDOWS
```
2. **Use an Existing Token:**
2. **Use an Existing Token**:
```bash
python ticket.py token "your-32-char-token"
```
3. **Extract Information from a Ticket:**
3. **Extract Information from a Ticket**:
```bash
python ticket.py info "serialized-ticket-string"
```
## Advanced Features
### IP/MAC-Based DRM Restriction Circumvention
> [!WARNING]
> Avoid using the same account across multiple regions or devices simultaneously, as it could lead to account suspension or banning.
Some DRM-protected services may block access based on the IP or MAC address of the user. To avoid this, the tool includes a **mocking server** that can spoof the device identity and circumvent such restrictions.
To run the server:
```bash
python server.py --email "user@example.com"
```
At the same time, enable the mock rules in HTTP Toolkit that are associated with DRM services.
## Common Issues
- **Invalid Token Error:** Ensure that your token is exactly 32 characters long. If it's shorter or longer, regenerate it or verify the token source.
- **Expired License:** If you encounter an expired license error, check the expiration date of your ticket using the `info` command and extend it by generating a new ticket.
- **DRM Block:** If the software blocks your IP/MAC address, ensure you're using the correct DRM circumvention server configuration.
- **Invalid Token Error**: Ensure that your token is exactly 32 characters long. If it's shorter or longer, regenerate it or verify the token source.
- **Expired License**: If you encounter an expired license error, check the expiration date of your ticket using the `info` command and generate a new ticket if necessary.
- **DRM Block**: If the software blocks your IP/MAC address, verify that youre using the correct DRM circumvention server configuration.
## License
@ -134,4 +137,4 @@ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file
## Disclaimer
This tool is provided for **educational purposes only**. Unauthorized use of software tools to bypass security mechanisms, including licensing, may violate laws and terms of service. Always ensure compliance with software terms of use before attempting any modifications.
This tool is provided for **educational purposes only**. Unauthorized use of software tools to bypass security mechanisms, including licensing, may violate laws and terms of service. Always ensure compliance with software terms of use before attempting any modifications.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/images/ticket_info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,3 +1,5 @@
pathlib~=1.0.1
requests~=2.31.0
requests-toolbelt~=1.0.0
requests-toolbelt~=1.0.0
xmltodict~=0.13.0
flask~=3.0.3

View File

@ -3,25 +3,29 @@ import json
import re
import secrets
import string
from enum import Enum
import requests
import xmltodict
from flask import Flask, Response, jsonify, request
from pathlib import Path
from requests_toolbelt import MultipartEncoder
# Path to export data
EXPORTS = Path(__file__).parent / 'exports.json'
def parse_boundary(data: str) -> dict:
"""
Parse the multipart form data to extract fields.
Parse multipart form data to extract fields.
Parameters:
- data (str): The raw multipart form data as a string.
- data (str): Raw multipart form data as a string.
Returns:
- dict: A dictionary with form field names as keys and field values as values.
- dict: A dictionary with form field names as keys and values as values.
"""
fields = {}
# Split parts using the boundary (separator) and process each part
@ -38,11 +42,28 @@ def parse_boundary(data: str) -> dict:
class ServiceType(Enum):
STREAM = 'Stream' # StreamFab, PlayerFab
STREAM = 'Stream' # StreamFab
MUSIC = 'Music' # MusicFab
class Session:
"""
Session class to manage and generate random user-related data (email, MAC, etc.).
Attributes:
- DOMAINS (list): Predefined list of popular email domains.
- CHARACTERS (str): Character set used for generating random local email parts.
- type (ServiceType): The type of service (Stream or Music).
- max (int): Maximum number of session usages before resetting.
- export (bool): Flag to determine if data should be exported.
- running (dict): Stores information about the current active session.
Methods:
- email (property): Generates or returns the current session email.
- mac (property): Generates or returns the current session MAC address.
- patch(data: dict): Patches the incoming data with session-specific fields.
"""
DOMAINS = ['hotmail.com', 'gmail.com', 'yahoo.com', 'outlook.com', 'protonmail.com', 'yandex.com']
CHARACTERS = string.ascii_lowercase + string.digits + '.-'
@ -56,6 +77,12 @@ class Session:
@property
def email(self) -> str:
"""
Generate a random email address if not already set.
Returns:
- str: Randomly generated or pre-set email address.
"""
length = secrets.choice(range(5, 15))
return self._email or '{local}@{domain}'.format(
local=''.join(secrets.choice(self.CHARACTERS) for _ in range(length)),
@ -64,10 +91,19 @@ class Session:
@email.setter
def email(self, value: str) -> None:
"""
Set the email manually if provided.
"""
self._email = value
@property
def mac(self) -> str:
"""
Generate a random MAC address if not already set.
Returns:
- str: Randomly generated or pre-set MAC address.
"""
return self._mac or ':'.join([
'-'.join(f'{b:02x}' for b in secrets.token_bytes(6)),
'-'.join(f'{b:02x}' for b in secrets.token_bytes(6))
@ -75,10 +111,25 @@ class Session:
@mac.setter
def mac(self, value: str) -> None:
"""
Set the MAC address manually if provided.
"""
self._mac = value
def patch(self, data: dict) -> dict:
kid = data['KD']
"""
Patch the data dictionary with dynamic fields (email, mac, etc.).
Parameters:
- data (dict): Incoming data dictionary to be patched.
Returns:
- dict: Modified data dictionary with session-specific fields.
"""
# Use kid or current running session's kid
kid = data.get('KD', self.running.get('kid'))
# Initialize new session if no session exists or conditions change
if not self.running or self.running.get('kid') != kid or self.running.get('count') >= self.max:
self.running = {
'kid': kid,
@ -87,50 +138,76 @@ class Session:
'count': 0
}
# Update necessary fields
for key, value in data.items():
if key in ('MD'):
if key in ('MD', 'EM'):
data[key] = self.running['mac']
elif key in ('EM'):
data[key] = self.running['email']
elif key in ('PW', 'TK'):
data[key] = '' # Empty password/token
elif key in ('RT'):
data[key] = 'trial'
elif key in ('DS', 'IS', 'BI'):
# Random token for certain fields
data[key] = secrets.token_hex(16)
elif key in ('PS'):
data[key] = self.type.value
elif key in ('PW', 'TK'):
data[key] = secrets.token_hex(16)
# Generate an invalid KID
data['KD'] = secrets.token_hex(16)
elif key == 'DT' and self.export:
# Export data if 'DT' key and export is enabled
exports = json.loads(EXPORTS.read_bytes()) if EXPORTS.is_file() else {}
exports[data['PD']] = value
exports.setdefault(data['TB'], {}).setdefault(data['PD'], value)
EXPORTS.write_text(json.dumps(exports, indent=2))
self.running['count'] += 1
return data
# Initialize session and Flask app
session = Session()
app = Flask(__name__)
app.config.update(ALLOWED_HOSTS=['127.0.0.1', 'localhost'])
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['POST', 'GET'])
@app.route('/<path:path>', methods=['POST'])
def catch_all(path: str) -> Response:
"""
Catch-all route to proxy requests.
Parses the multipart form data, modifies it, and forwards the request.
Parameters:
- path (str): The request path for matching.
Returns:
- Response: A Flask Response object containing the forwarded request's response.
"""
global session
# Remove unnecessary headers
headers = dict(request.headers)
del headers['Connection']
del headers['Content-Length']
headers.pop('Connection', None)
headers.pop('Content-Length', None)
# Get raw body data
body = request.get_data()
boundary = parse_boundary(body.decode('utf-8'))
patched = session.patch(boundary) # TODO: fix patch
# patched = boundary
mp_encoder = MultipartEncoder(patched)
# Extract boundary from content-type
content_type = headers.get('Content-Type', '')
boundary_match = re.search(r'boundary=(.*)', content_type)
if not boundary_match:
return Response(status=400, response='Invalid or missing boundary')
# Parse and patch the multipart form data
boundary_data = parse_boundary(body.decode('utf-8'))
patched = session.patch(boundary_data)
# Re-encode patched data using MultipartEncoder
mp_encoder = MultipartEncoder(fields=patched)
headers['Content-Type'] = mp_encoder.content_type
body = mp_encoder.read()
# Forward the request to the same URL over HTTPS
# Forward the request to the target URL over HTTPS
r = requests.request(
method=request.method,
url=request.url.replace('http://', 'https://'),
@ -141,11 +218,41 @@ def catch_all(path: str) -> Response:
)
# Return the response from the forwarded request
return Response(status=r.status_code, response=r.content)
return Response(status=r.status_code, response=r.content, headers={'Content-Type': 'text/html; charset=UTF-8'})
@app.route('/session', methods=['GET'])
@app.route('/auth/trial_disc.php', methods=['POST'])
def trial_disc() -> Response:
"""
Trial endpoint to provide disc information with MacID.
Returns:
- Response: XML response containing trial disc information with the generated MacID.
"""
global session
params = request.args.to_dict()
data = {
'TrialOpenDiscInfo': {
'@Client': params.get('Client', 49),
'@MacID': params.get('MacID', session.mac)
}
}
content = xmltodict.unparse(data, pretty=False, full_document=True).encode('utf-8')
return Response(status=200, response=content, headers={'Content-Type': 'text/html'})
@app.route('/debug', methods=['GET'])
def session_info() -> Response:
"""
Debug endpoint to display session information (email, MAC, etc.).
Returns:
- Response: JSON response with current session data.
"""
global session
return jsonify({
'email': session.email,
'mac': session.mac,
@ -155,13 +262,13 @@ def session_info() -> Response:
# Add the catch_all route to Flask
app.add_url_rule('/', 'catch_all', catch_all, defaults={'path': ''})
app.add_url_rule('/<path:path>', 'catch_all', catch_all, defaults={'path': ''})
app.config.update(ALLOWED_HOSTS=['127.0.0.1', 'localhost'])
if __name__ == '__main__':
# Set up argument parsing
parser = argparse.ArgumentParser(description='DVDFab-Server: ')
parser = argparse.ArgumentParser(description='DVDFab-Server: A server for proxying requests and managing sessions for DVDFab-related services.')
# Command-line arguments
parser.add_argument('--email', type=str, metavar='<email>', help='Email address (default: random)')
@ -173,17 +280,12 @@ if __name__ == '__main__':
# Parse the arguments
args = parser.parse_args()
try:
# Set session values from the command-line arguments
session.email = args.email
session.mac = args.mac
session.type = ServiceType[args.type]
session.max = args.max
session.export = args.export
# Set session parameters based on arguments
session.email = args.email
session.mac = args.mac
session.type = ServiceType[args.type]
session.max = args.max
session.export = args.export
# Start the Flask app
app.run(host='127.0.0.1', port=5000, debug=True)
except KeyboardInterrupt:
pass
except Exception as e:
print(f'[!] {e}')
# Start the Flask app
app.run(host='127.0.0.1', port=5000, debug=False)

File diff suppressed because it is too large Load Diff