This commit is contained in:
katboi01 2025-01-24 12:11:57 +01:00
commit 222c73f667
5 changed files with 300 additions and 0 deletions

145
dmmBypass.py Normal file
View File

@ -0,0 +1,145 @@
import os
import sys
import wmi
import hashlib
import requests
import subprocess
import urllib.parse
import dmmUpdater
from uuid import getnode
from bs4 import BeautifulSoup
from pypasser import reCaptchaV3
def get_hash(data):
sha_obj = hashlib.sha256()
sha_obj.update(str(data).encode())
hash_hex = sha_obj.hexdigest()
return hash_hex
def get_mac():
mac = getnode()
return ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2)).lower()
def get_motherboard():
return wmi.WMI().Win32_BaseBoard()[0].SerialNumber
def retrieve_login_token(session : requests.Session):
try:
print("Retrieving login form")
url = "https://accounts.dmm.com/service/login/password"
result = session.get(url)
page = BeautifulSoup(result.content, 'html.parser')
token = page.find('input', attrs={"name":"token"}).get("value")
return token
except Exception as e:
print("Failed to retrieve login form:", e)
return None
def retrieve_captcha_token():
try:
captcha = reCaptchaV3("https://www.google.com/recaptcha/enterprise/anchor?ar=1&k=6LfZLQEVAAAAAC-8pKwFNuzVoJW4tfUCghBX_7ZE&co=aHR0cHM6Ly9hY2NvdW50cy5kbW0uY29tOjQ0Mw..&hl=ja&v=1Bq_oiMBd4XPUhKDwr0YL1Js&size=invisible")
return captcha
except Exception as e:
print("Failed to solve captcha:", e)
return None
def retrieve_auth_keys(login, password, token, captcha, session : requests.Session):
try:
print("Logging in")
url = "https://accounts.dmm.com/service/login/password/authenticate"
data = f"token={token}&login_id={login}&password={password}&prompt=&device=games-player&recaptchaToken={captcha}"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
result = session.post(url, data, headers=headers)
cookies = result.cookies.get_dict()
return cookies["login_secure_id"], cookies["login_session_id"]
except Exception as e:
print("Failed to log in:", e)
return None, None
def retrieve_update_params(game_id, login_secure, login_session, use_proxy):
try:
print("Retrieving update file list")
data = {"product_id":game_id,"game_type":"GCL","game_os":"win"}
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
cookies = {"login_secure_id":login_secure, "login_session_id":login_session}
url = "https://katworks.sytes.net/KF/Api/DMM/filelist" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/r2/filelist/cl"
result = requests.post(url, cookies=cookies, headers=headers, json=data)
data = result.json()["data"]
game_version = data["latest_version"]
print("Latest version:", game_version)
file_list_url = data["file_list_url"]
file_list_params = data["sign"]
file_list_params = "?" + file_list_params.replace(";", "&").replace("CloudFront-", "")
return file_list_url, file_list_params
except Exception as e:
print("Failed to retrieve update file list:", e)
return
def retrieve_launch_params(game_id, mac_addr, hdd_serial, motherboard, login_secure, login_session, use_proxy):
try:
print("Retrieving launch arguments")
data = {"product_id":game_id,"game_type":"GCL","game_os":"win","launch_type":"LIB","mac_address":mac_addr,"hdd_serial":hdd_serial,"motherboard":motherboard,"user_os":"win"}
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
cookies = {"login_secure_id":login_secure, "login_session_id":login_session}
url = "https://katworks.sytes.net/KF/Api/DMM/launch" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/r2/launch/cl"
result = requests.post(url, cookies=cookies, headers=headers, json=data)
data = result.json()["data"]
return data["execute_args"]
except Exception as e:
print("Failed to retrieve launch arguments:", e)
return None
def main(args):
if len(args) != 7:
print("Usage:",
"\tpython dmmBypass.py game_id game_path email password update_game use_proxy",
"\t- game_id: DMM code name of the game",
"\t- game_path: full path to the game .exe. Wrap in \" if there are spaces in the path",
"\t- email, password: dmm credentials",
"\t- update_game: \"true\" to check for game update before launching",
"\t- use_proxy: \"true\" to send required request through Katboi VPN. Otherwise use your own VPN",
"\texample: python dmmBypass.py kfp2g \"D:\Games\KFP2G\けもフレ3.exe\" kat@email.com abc123 true", sep="\n")
return
game_id = args[1]
exe_location = args[2]
login = urllib.parse.quote_plus(args[3])
password = urllib.parse.quote_plus(args[4])
update_game = args[5].lower() == "true"
use_proxy = args[6].lower() == "true"
mac_addr = get_mac()
hdd_serial = get_hash('')
motherboard = get_hash(get_motherboard())
with requests.Session() as session:
token = retrieve_login_token(session)
captcha = retrieve_captcha_token()
if token == None or captcha == None:
return
#auth keys are also saved as cookies in session
login_secure, login_session = retrieve_auth_keys(login, password, token, captcha, session)
if not use_proxy: input("Enable VPN now and press Enter")
if update_game:
file_list_url, file_access_params = retrieve_update_params(game_id, login_secure, login_session, use_proxy)
if file_list_url == None or file_access_params == None:
return
dmmUpdater.update_game(os.path.dirname(exe_location), file_list_url, file_access_params)
execute_args = retrieve_launch_params(game_id, mac_addr, hdd_serial, motherboard, login_secure, login_session, use_proxy)
if not use_proxy: input("Disable VPN now and press Enter")
print("Starting game")
args = [exe_location] + execute_args.split()
print(args)
subprocess.Popen(args, start_new_session=True)
input("Done. Press enter to exit")
args = sys.argv
main(args)

80
dmmUpdater.py Normal file
View File

@ -0,0 +1,80 @@
import os
import hashlib
import requests
import urllib.parse
from urllib.request import urlretrieve
import sys
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+
"""https://stackoverflow.com/questions/3160699/python-progress-bar"""
count = len(it)
if count == 0: return
def show(j):
x = int(size*j/count)
print("{}[{}{}] {}/{}".format(prefix, "#"*x, "."*(size-x), j, count),
end='\r', file=out, flush=True)
show(0)
for i, item in enumerate(it):
yield item
show(i+1)
print("\n", flush=True, file=out)
def get_file_list(url):
url = "https://apidgp-gameplayer.games.dmm.com" + url
print("Retrieving file list from " + url)
data = requests.get(url).json()["data"]
return data["domain"], data["file_list"]
def get_file_hash(file_path):
if not os.path.exists(file_path):
return None
with open(file_path, "rb") as f:
file_hash = hashlib.md5()
while chunk := f.read(8192):
file_hash.update(chunk)
return file_hash.hexdigest()
def update_game(game_path, files_url, files_param):
server_url, server_files = get_file_list(files_url)
server_file_dict = {file["local_path"]: file for file in server_files}
local_files = [os.path.join(dp, f).replace("\\", "/") for dp, dn, filenames in os.walk(game_path) for f in filenames]
local_file_dict = {"/" + os.path.relpath(r, game_path).replace("\\", "/"): {"abs_path":r, "hash":""} for r in local_files if not "BepInEx" in r}
files_to_download = []
files_to_delete = []
for server_file_key in server_file_dict.keys():
server_file = server_file_dict[server_file_key]
if server_file_key in local_file_dict:
local_file = local_file_dict[server_file_key]
if server_file["force_delete_flg"]:
files_to_delete.append(local_file["abs_path"])
else:
local_file["hash"] = get_file_hash(local_file["abs_path"])
if server_file["check_hash_flg"] and local_file["hash"] == server_file["hash"]:
continue
download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param
download_path = game_path.replace("\\", "/") + server_file_key
files_to_download.append({"url":download_url, "path":download_path})
else:
download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param
download_path = game_path.replace("\\", "/") + server_file_key
files_to_download.append({"url":download_url, "path":download_path})
print("Files to download:", len(files_to_download))
for file in progressbar(files_to_download, "Downloading: ", 40):
url, path = file["url"], file["path"]
os.makedirs(os.path.dirname(path), exist_ok=True)
urlretrieve(url, path)
# #files_to_delete is unused until fully tested
# for file in files_to_delete:
# os.remove(file)
return True

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
beautifulsoup4
PyPasser
wmi

36
run_KF3.bat Normal file
View File

@ -0,0 +1,36 @@
@echo off
chcp 65001
setlocal enabledelayedexpansion
set file_name="kfp2g.cfg"
IF NOT EXIST %file_name% (
set /p null="Make sure python is installed. In next step, required packages will be installed. Press Enter to continue"
pip install -r requirements.txt
set /p file_path=Enter full file path to KF3 .exe:
set /p dmm_login=DMM Login:
set /p dmm_password=DMM Password:
set /p confirm="Your login tokens will be sent through Katboi's VPN machine, is that ok? Personal VPN is required if not (yes/no):"
echo !confirm!
if /i "!confirm!"=="yes" (
set use_proxy=true
) else (
set use_proxy=false
)
echo !file_path!> %file_name%
echo !dmm_login!>> %file_name%
echo !dmm_password!>> %file_name%
echo !use_proxy!>> %file_name%
) ELSE (
< %file_name% (
set /p file_path=
set /p dmm_login=
set /p dmm_password=
set /p use_proxy=
)
echo Loaded settings from %file_name%
)
python dmmBypass.py kfp2g %file_path% %dmm_login% %dmm_password% false %use_proxy%
pause

36
update_and_run_KF3.bat Normal file
View File

@ -0,0 +1,36 @@
@echo off
chcp 65001
setlocal enabledelayedexpansion
set file_name="kfp2g.cfg"
IF NOT EXIST %file_name% (
set /p null="Make sure python is installed. In next step, required packages will be installed. Press Enter to continue"
pip install -r requirements.txt
set /p file_path=Enter full file path to KF3 .exe:
set /p dmm_login=DMM Login:
set /p dmm_password=DMM Password:
set /p confirm="Your login tokens will be sent through Katboi's VPN machine, is that ok? Personal VPN is required if not (yes/no):"
echo !confirm!
if /i "!confirm!"=="yes" (
set use_proxy=true
) else (
set use_proxy=false
)
echo !file_path!> %file_name%
echo !dmm_login!>> %file_name%
echo !dmm_password!>> %file_name%
echo !use_proxy!>> %file_name%
) ELSE (
< %file_name% (
set /p file_path=
set /p dmm_login=
set /p dmm_password=
set /p use_proxy=
)
echo Loaded settings from %file_name%
)
python dmmBypass.py kfp2g %file_path% %dmm_login% %dmm_password% true %use_proxy%
pause