You've already forked JapariBypass
							
							init
This commit is contained in:
		
							
								
								
									
										145
									
								
								dmmBypass.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								dmmBypass.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										80
									
								
								dmmUpdater.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										3
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | beautifulsoup4 | ||||||
|  | PyPasser | ||||||
|  | wmi | ||||||
							
								
								
									
										36
									
								
								run_KF3.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								run_KF3.bat
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										36
									
								
								update_and_run_KF3.bat
									
									
									
									
									
										Normal 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 | ||||||
		Reference in New Issue
	
	Block a user