├── .gitignore ├── .gitmodules ├── README.md └── project ├── advhd ├── advhd.mk ├── src │ ├── advhd_arcv1.py │ ├── advhd_arcv2.py │ ├── advhd_patch.c │ ├── advhd_pna.py │ ├── advhd_ws2.py │ ├── advhd_wsc.py │ └── compat │ │ ├── commdef_v100.h │ │ ├── libtext_v620.py │ │ ├── libutil_v600.py │ │ ├── stb_minhook_v1332.h │ │ ├── windllin_v321.py │ │ └── winhook_v330.h └── task │ └── task_blackishhouse │ ├── Makefile │ ├── build.sh │ └── init.sh ├── artemis └── src │ └── artemis_pf8.py ├── azsystem ├── lamune.mk └── src │ ├── compat │ ├── bintext_v580.py │ ├── stb_image_v2270.h │ ├── stb_zip_v220.h │ ├── windllin_v320.py │ ├── winhook_v310.h │ └── winpe_v350.h │ ├── lamune_asbtext.py │ ├── lamune_hook.js │ └── lamune_patch.c ├── bruns └── src │ └── bruns_decrypt.c ├── criware ├── iwaihime.mk └── src │ ├── compat │ ├── commdef_v110.h │ ├── libfont_v180.py │ ├── stb_minhook_v1332.h │ ├── winversion_v100.def │ └── winversion_v100.h │ ├── iwaihime_font.py │ ├── iwaihime_patch.c │ ├── iwaihime_sn.c │ └── xtx_font.py ├── cycrose └── src │ ├── baranoki_psp_boot.py │ ├── baranoki_psp_fontfnt.py │ ├── baranoki_psp_fontp.py │ ├── baranoki_psp_pk.py │ ├── baranoki_psp_pktext.py │ ├── baranoki_psp_vmc.py │ ├── baranoki_psp_zp.py │ └── compat │ ├── bintext_v440.py │ └── libfont_v220.py ├── eldia ├── make_libkanda_fontmap.bat └── src │ ├── compat │ └── bintext_v430.py │ ├── kanda_switch_fontmap.c │ ├── kanda_switch_fontmap.py │ └── kanda_switch_rs4.py ├── entergram └── src │ └── 9nine_switch_fnt.py ├── exhibit ├── soraironoorgan.mk └── src │ ├── compat │ └── winhook_v310.h │ └── soraironoorgan_patch.c ├── ffa ├── amanomiko.mk └── src │ ├── amanomiko_install.bat │ ├── amanomiko_lzss.py │ ├── amanomiko_patch.c │ ├── amanomiko_pt1.py │ ├── amanomiko_so4.py │ ├── compat │ ├── bintext_v580.py │ ├── lzss_v1000.h │ ├── stb_minhook_v1330.h │ ├── stb_zip_v220.h │ ├── windllin_v320.py │ ├── winhook_v310.h │ └── winpe_v350.h │ └── liblzss20.c ├── gss └── src │ └── gss_arc.cs ├── hibiki └── src │ ├── hibiki_kstext.py │ └── hibiki_rename_picture.py ├── hobibox ├── src │ ├── compat │ │ ├── bintext_v580.py │ │ └── libfont_v240.py │ ├── liblzss64.dll │ ├── narcissus_psp_2bppfont.py │ ├── narcissus_psp_lbg.py │ ├── narcissus_psp_lzss.py │ ├── narcissus_psp_sn.py │ └── narcissus_psp_sntext.py └── task │ └── task_narcissuspsp │ ├── _env.bat │ ├── build_1font.bat │ ├── build_2sn.bat │ ├── build_3lbg.bat │ ├── build_3sys.bat │ ├── build_4eboot.bat │ ├── convert_fixlbg.bat │ ├── convert_invfixlbg.bat │ ├── extract_lbg.bat │ ├── extract_lzss.bat │ ├── extract_sn.bat │ ├── init.bat │ ├── run.bat │ └── send.bat ├── hunex └── src │ ├── hunex_hlzs.py │ ├── hunex_hpb.py │ ├── meikoi_dump.c │ └── meikoi_dump.js ├── ig ├── ig_redirect.mk └── src │ ├── compat │ └── winhook_v310.h │ ├── flowers1_pc_dumpscript.py │ ├── flowers2_pc_dumpscript.py │ ├── flowers3_pc_dumpscript.py │ ├── flowers4_pc_dumpscript.py │ ├── flowers_pc_mergetext.py │ └── ig_redirect.c ├── kid └── src │ ├── kid_psp_bip.py │ ├── kid_psp_bip2.py │ └── lzss.h ├── koei └── src │ ├── corda_cdar.py │ ├── haruka_cdar.py │ └── psptm2.py ├── konami └── src │ ├── gs3_evsc.py │ ├── zbintext_v053.py │ └── zlibtext_v022.py ├── krkr ├── krkrtool.mk ├── sdhime.mk └── src │ ├── compat │ ├── commdef_v110.h │ ├── stb_minhook_v1332.h │ ├── tp_stub.cpp │ ├── tp_stub.h │ ├── winhook_v350.h │ ├── winversion_v100.def │ └── winversion_v100.h │ ├── krkr_hxv4_dumphash.cpp │ ├── krkr_hxv4_dumpkey.js │ ├── krkr_hxv4_patch.cpp │ ├── krkr_text.py │ ├── krkr_xp3.py │ ├── sdhime_patch.c │ ├── sdhime_xp3enc.cpp │ └── sdhime_xp3enc.def ├── livemaker ├── aikimi.mk └── src │ ├── aikimi_loader.c │ ├── aikimi_patch.c │ ├── compat │ ├── detours_v4010.h │ ├── detours_v4010.lib │ ├── stb_minhook_v1330.h │ ├── winhook_v310.h │ └── winpe_v350.h │ └── kernel32.def ├── majiro ├── majiro.mk ├── src │ ├── compat │ │ ├── bintext_v200.h │ │ ├── commdef_v100.h │ │ ├── libtext_v610.py │ │ ├── libutil_v600.py │ │ ├── windllin_v321.py │ │ ├── winhook_v330.h │ │ └── winpe_v370.h │ ├── majiro_arc.py │ ├── majiro_mjiltext.py │ ├── majiro_mjo.py │ ├── majiro_patch.c │ ├── winterpolaris_hook.js │ └── winterpolaris_patch.c ├── task │ └── task_sorairo │ │ ├── Makefile │ │ ├── build.sh │ │ └── init.sh ├── tool │ └── mjotool2 │ │ ├── README.md │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── _research.py │ │ ├── _util.py │ │ ├── analysis.py │ │ ├── assembler.py │ │ ├── crypt.py │ │ ├── flags.py │ │ ├── known_hashes │ │ ├── __init__.py │ │ └── _hashes.py │ │ ├── mjs │ │ ├── __init__.py │ │ ├── identifiers.py │ │ └── mjsreader.py │ │ ├── opcodes.py │ │ ├── script.py │ │ └── sheets │ │ ├── __init__.py │ │ ├── csvsheet.py │ │ ├── googlesheets.py │ │ ├── majirodata.py │ │ └── rowtypes.py └── winterpolaris.mk ├── nippon1 ├── src │ ├── compat │ │ └── bintext_v580.py │ ├── ykcmp.py │ ├── yomawari3_switch_fad.py │ └── yomawari3_switch_nltx.py └── task │ └── task_yomawari3 │ ├── _env.bat │ ├── build_1font.bat │ ├── build_2database.bat │ ├── build_3texture.bat │ ├── extract_nltxs.bat │ ├── init.bat │ ├── run.bat │ └── send.bat ├── nvl └── src │ └── nvl_asar.py ├── onscripter ├── make_ons_decryptnt3.bat ├── nscript.mk └── src │ ├── nscript_patch.c │ └── ons_decryptnt3.c ├── prototype └── src │ ├── compat │ ├── bintext_v400.py │ └── libfont_v180.py │ ├── flowers1-2_psv_pak.py │ ├── flowers3_psv_pak.py │ ├── flowers4_psv_pak.py │ ├── island_psv_pak.py │ ├── prot_psv_4bppfnt.py │ ├── prot_psv_dat.py │ └── prot_psv_psbtext.py ├── qt ├── CMakeLists.txt ├── qttool.mk └── src │ ├── compat │ ├── commdef_v110.h │ ├── winversion_v100.def │ └── winversion_v100.h │ └── qfile_dump.cpp ├── renpy └── src │ └── skyblue_wjz.py ├── systemnnn ├── src │ ├── compat │ │ ├── commdef_v100.h │ │ ├── stb_image_v2270.h │ │ ├── stb_minhook_v1332.h │ │ ├── windllin_v321.py │ │ └── winhook_v330.h │ ├── systemnnn_patch.c │ └── systemnnn_spt.py ├── systemnnn.mk └── task │ └── task_wajinIbunroku │ ├── Makefile │ ├── build.sh │ └── init.sh ├── tyrano ├── make_tyrano_extractexe.bat └── src │ ├── make_tyrano_extractexe.bat │ ├── qbit_hook_obb.py │ ├── qbit_text.py │ └── tyrano_extractexe.c ├── unity ├── unity_assetbundle.py └── unity_globalmeta.py └── yuris ├── akaihana.mk ├── src ├── akaihana_patch.c ├── compat │ ├── bintext_v580.py │ └── windllin_v320.py └── yuris_patch.c └── yuris.mk /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyd 3 | __pycache__ 4 | *.o 5 | *.obj 6 | *..iobj 7 | *.pdb 8 | *.ipdb 9 | *.exp 10 | *.ilk 11 | .vs 12 | .vscode 13 | 14 | dvfs 15 | 16 | tmp/* 17 | project/**/asset/build 18 | project/**/task/**/workflow 19 | project/**/task/**/_env.* 20 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuriSizuku/GalgameReverse/e9e309986dd51ed65fc7c26c87de1d5f516cbc89/.gitmodules -------------------------------------------------------------------------------- /project/advhd/advhd.mk: -------------------------------------------------------------------------------- 1 | CC:=clang 2 | BUILD_DIR:=asset/build 3 | INCS:=-Isrc/compat 4 | LIBS:=-luser32 -lgdi32 -lshlwapi -ladvapi32 -lpsapi 5 | CFLAGS:=-ffunction-sections -fdata-sections 6 | LDFLAGS:= 7 | 8 | ifdef DEBUG 9 | CFLAGS+=-g -D_DEBUG 10 | else 11 | CFLAGS+=-Os 12 | endif 13 | 14 | ifneq (,$(findstring clang, $(CC))) # for llvm-mingw 15 | CFLAGS+=-m32 -gcodeview -Wl,--pdb=$(BUILD_DIR)/advhd_patch.pdb 16 | LDFLAGS+= -Wl,--gc-sections 17 | else ifneq (,$(findstring gcc, $(CC))) # for mingw-w64 18 | CFLAGS+=-m32 19 | LDFLAGS+= -Wl,--gc-sections \ 20 | -static-libgcc -static-libstdc++ \ 21 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 22 | -Wl,--no-whole-archive 23 | else ifneq (,$(findstring tcc, $(CC))) # for tcc 24 | CFLAGS+=-m32 25 | else # for previous llvm clang with msvc 26 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 27 | LDFLAGS+=-Wl,/OPT:REF # for llvm 28 | endif 29 | 30 | all: prepare advhd_patch 31 | 32 | prepare: 33 | @mkdir -p $(BUILD_DIR) 34 | 35 | advhd_patch: src/advhd_patch.c 36 | @echo "## $@" 37 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 38 | -D USECOMPAT \ 39 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 40 | @rm -rf $(BUILD_DIR)/$@.exp 41 | @rm -rf $(BUILD_DIR)/$@.lib 42 | @rm -rf $(BUILD_DIR)/$@.def 43 | 44 | .PHONY: all prepare advhd_patch -------------------------------------------------------------------------------- /project/advhd/src/advhd_arcv2.py: -------------------------------------------------------------------------------- 1 | """ 2 | export or build arc v2 for willplus advhd 3 | tested in BlackishHouse (v1.6.2.1) 4 | v0.1, developed by devseed 5 | """ 6 | 7 | import os 8 | import sys 9 | import mmap 10 | import struct 11 | from io import BytesIO 12 | from collections import namedtuple 13 | from typing import List, Tuple 14 | 15 | advhdv2_fileentry_t = namedtuple('advhdentry_t', ['size', 'offset', 'name']) 16 | 17 | def ror(d, n): 18 | n &= 7 19 | return (d>>n | d<<(8-n)) & 0xff 20 | 21 | def rol(d, n): 22 | n &= 7 23 | return (d<>(8-n)) & 0xff 24 | 25 | def parse_arc(data: bytes) -> Tuple[int, List[advhdv2_fileentry_t]]: 26 | n, index_size = struct.unpack(" 3 else "./out" 113 | export_arc(sys.argv[2], outpath) 114 | elif sys.argv[1].lower() == 'b': 115 | outpath = sys.argv[3] if len(sys.argv) > 3 else "out.arc" 116 | build_arc(sys.argv[2], outpath) 117 | else: raise ValueError(f"unknow format {sys.argv[1]}") 118 | 119 | if __name__ == '__main__': 120 | # debug() 121 | main() 122 | pass -------------------------------------------------------------------------------- /project/advhd/src/advhd_pna.py: -------------------------------------------------------------------------------- 1 | """ 2 | export or import pna for willplus advhd, 3 | tested in BlackishHouse (v1.6.2.1) 4 | v0.1.1, developed by devseed 5 | """ 6 | 7 | import os 8 | import sys 9 | import struct 10 | import numpy as np 11 | from PIL import Image 12 | from io import SEEK_END, SEEK_SET, BytesIO 13 | from glob import glob 14 | from collections import namedtuple 15 | from typing import List 16 | 17 | pngentry_t = namedtuple('pngentry_t', ['x', 'y', 'w', 'h', 'offset', 'size']) 18 | 19 | def parse_pna(data): 20 | pngentries: List[pngentry_t] = [] 21 | n = int.from_bytes(data[0x10: 0x14], 'little', signed=False) 22 | pngoffset = 0x14 + n*0x28 23 | for i in range(n): 24 | cur = 0x14 + i*0x28 + 0x8 25 | x, y, w, h = struct.unpack("<4I", data[cur: cur+0x10]) 26 | cur = 0x14 + i*0x28 + 0x24 27 | size, = struct.unpack("0x{bufio.tell():x}" 69 | f", size {entry.size:x}->{os.stat(inpath).st_size:x}") 70 | img = np.array(Image.open(inpath)) 71 | if img.shape[2] > 3: # fix alpha 0 to all pixel 0 72 | amask = np.expand_dims(img[:, :, 3] > 0, axis=2) 73 | img = img * amask 74 | _imgio = BytesIO() 75 | Image.fromarray(img).save(_imgio, format='png') 76 | bufio.write(_imgio.getbuffer()) 77 | entries[i] = pngentry_t( 78 | entry.x, entry.y, entry.w, entry.h, 79 | bufio.tell(), len(_imgio.getbuffer())) 80 | else: 81 | bufio.write(data[entry.offset: entry.offset + entry.size]) 82 | 83 | # write header 84 | for i, entry in enumerate(entries): 85 | offset = 0x14 + i*0x28 + 0x24 86 | bufio.seek(offset, SEEK_SET) 87 | bufio.write(int.to_bytes( # only update size 88 | entry.size, 4, 'little', signed=False)) 89 | 90 | if outpath!="": 91 | with open(outpath, 'wb') as fp: 92 | fp.write(bufio.getbuffer()) 93 | 94 | return bufio.getbuffer() 95 | 96 | def debug(): 97 | # export_pna("./build/intermediate/SysGraphic/Sys_CharSelect.pna") 98 | import_pna("./buildv2.1/intermediate/SysGraphic_png/Sys_title", "./buildv2.1/intermediate/SysGraphic/Sys_title.pna") 99 | pass 100 | 101 | def main(): 102 | if len(sys.argv) < 3: 103 | print("advhd_pna e inpath [outdir]") 104 | print("advhd_pna i indir orgpath [outpath]") 105 | return 106 | if sys.argv[1].lower() == 'e': 107 | outpath = sys.argv[3] if len(sys.argv) > 3 else "./out" 108 | export_pna(sys.argv[2], outpath) 109 | elif sys.argv[1].lower() == 'i': 110 | outpath = sys.argv[4] if len(sys.argv) > 4 else "out.pna" 111 | import_pna(sys.argv[2], sys.argv[3], outpath) 112 | else: raise ValueError(f"unknow format {sys.argv[1]}") 113 | 114 | if __name__ == '__main__': 115 | # debug() 116 | main() 117 | pass 118 | 119 | """ 120 | history: 121 | v0.1, support BlackishHouse (v1.6.2.1) 122 | v0.1.1, fix png alpha problem 123 | """ -------------------------------------------------------------------------------- /project/advhd/task/task_blackishhouse/Makefile: -------------------------------------------------------------------------------- 1 | # required variables: 2 | # WORK_DIR, build workflow dir 3 | # SRC_DIR, project src dir, usually ../../src 4 | # TOOL_DIR, external tool dir, usually ../../tool 5 | 6 | # optional variables 7 | # BASE_DIR, project basedir 8 | # GAME_EXEC, use which command to launch game 9 | # GAME_FILE, origin game package path 10 | # GAME_DIR, game dir for testing 11 | 12 | # usage: 13 | # at first, put the vairable in _env.sh file 14 | # in linux, "source ./_env.sh" 15 | # in windows, "msys2_shell -here -no-start -defterm -full-path" to activate, then "source ./_env.sh" 16 | 17 | # _env.sh example 18 | # export GAME_NAME=BlackishHouse 19 | # export GAME_ID=vndb-v17853 20 | # if [ -n "$(uname -a | grep Msys)" ]; then 21 | # export BASE_DIR=/d/Downloads/$GAME_NAME 22 | # export GAME_EXEC=start 23 | # else 24 | # LOCPATH=~/.wine/locale 25 | # # zh_CN.UTF-8 not worked 26 | # export BASE_DIR=~/Downloads/$GAME_NAME 27 | # export GAME_EXEC=wine 28 | # fi 29 | # export GAME_FILE=$BASE_DIR/${GAME_ID}.7z 30 | # export GAME_DIR=$BASE_DIR/${GAME_ID}_rebuild 31 | # export WORK_DIR=$BASE_DIR/workflow 32 | # export SRC_DIR=../../src 33 | # export TOOL_DIR=../../tool 34 | 35 | SHELL := /bin/bash 36 | 37 | all: 38 | @echo build BlackishHouse chspatch 39 | @make build_1ws2 40 | @make build_1lua 41 | @make build_2pna 42 | @make build_3arcv2 43 | @make build_4dll 44 | @make build_4exe 45 | 46 | link: 47 | @if ! [ -d workflow ]; then \ 48 | ln -s $(WORKFLOW_DIR) workflow;\ 49 | fi 50 | 51 | unlink: 52 | @rm -rf workflow 53 | 54 | init_workdir init_gamedir init_mingwsdk: 55 | @./init.sh $@ 56 | 57 | build_1ws2 build_1lua build_2pna build_3arcv2 build_4dll build_4exe: init_workdir 58 | @./build.sh $@ 59 | 60 | release_patch: 61 | @./build.sh $@ 62 | 63 | run: 64 | @cd $(GAME_DIR);$(GAME_EXEC) AdvHD_chs.exe 65 | 66 | # vscode launch.json config 67 | # can not pause while running, can only set breakpoint on pause or before launch 68 | # "name": "linux wajin_asaki", 69 | # "type": "cppdbg", 70 | # "request": "launch", 71 | # "program": "AdvHD_chs.exe", 72 | # "args": [], 73 | # "cwd": "~/Downloads/BlackishHouse/vndb-v17853_rebuild/", 74 | # "stopAtEntry": false, 75 | # "environment": [], 76 | # "MIMode": "gdb", 77 | # "miDebuggerPath": "/usr/bin/i686-w64-mingw32-gdb", 78 | # "miDebuggerServerAddress": "localhost:1234", 79 | run_gdbserver: 80 | @cd $(GAME_DIR); LOCPATH=~/.wine/locale LANG=zh_CN.UTF-8 \ 81 | wine Z:/usr/share/win32/gdbserver.exe localhost:1234 AdvHD_chs.exe 82 | 83 | send: init_gamedir 84 | @cp -rf $(WORK_DIR)/5.result/* $(GAME_DIR) 85 | 86 | test: 87 | @make send 88 | @make run 89 | 90 | clean: 91 | @rm -f $(WORK_DIR)/*.7z 92 | @rm -rf ${WORK_DIR}/5.result 93 | 94 | .PHONY: all link unlink \ 95 | init_workdir init_gamedir \ 96 | build_1ws2 build_1lua build_2pna build_3arcv2 build_4dll build_4exe \ 97 | release_patch run send test clean -------------------------------------------------------------------------------- /project/advhd/task/task_blackishhouse/build.sh: -------------------------------------------------------------------------------- 1 | build_1ws2() { 2 | echo "## build_1ws2" 3 | rios=$(find ${WORK_DIR}/1.origin -type f -name Rio*.arc -exec basename -s .arc {} \;|sort) 4 | for rio in $rios; do 5 | cp -rf ${WORK_DIR}/2.pre/$rio/* ${WORK_DIR}/4.post/$rio 6 | if [ -d ${WORK_DIR}/3.edit/${rio}_ftext ]; then 7 | echo ${rio}_ftext 8 | for infile in $(ls ${WORK_DIR}/3.edit/${rio}_ftext/*.txt); do 9 | inname=$(basename $infile .txt) 10 | echo ${rio}/$inname # .ws2 11 | python -B ${SRC_DIR}/advhd_ws2.py icp936 $infile \ 12 | ${WORK_DIR}/2.pre/${rio}/$inname \ 13 | ${WORK_DIR}/4.post/${rio}/$inname 14 | done 15 | fi 16 | 17 | if [ -d ${WORK_DIR}/3.edit/${rio}_ftext2 ]; then 18 | echo ${rio}_ftext2 19 | for infile in $(ls ${WORK_DIR}/3.edit/${rio}_ftext2/*.txt); do 20 | inname=$(basename $infile .txt) 21 | echo ${rio}/$inname # .ws2 22 | python -B ${SRC_DIR}/compat/libtext_v620.py insert \ 23 | ${WORK_DIR}/2.pre/${rio}/$inname $infile \ 24 | -o ${WORK_DIR}/4.post/${rio}/$inname -e gbk --bytes_padding 20 25 | done 26 | fi 27 | done 28 | } 29 | 30 | build_1lua() { 31 | echo "## build_1lua" 32 | cp -rf ${WORK_DIR}/2.pre/Script/* ${WORK_DIR}/4.post/Script 33 | for infile in $(ls ${WORK_DIR}/3.edit/Script_ftext/*.txt); do 34 | inname=$(basename $infile .txt) 35 | echo $inname 36 | python -B ${SRC_DIR}/compat/libtext_v620.py insert \ 37 | ${WORK_DIR}/2.pre/Script/$inname $infile \ 38 | -o ${WORK_DIR}/4.post/Script/$inname -e gbk --bytes_padding 20 39 | done 40 | } 41 | 42 | build_2pna() { 43 | echo "## build_2pna" 44 | cp -rf ${WORK_DIR}/2.pre/SysGraphic/* ${WORK_DIR}/4.post/SysGraphic # for build arc 45 | for inname in $(ls ${WORK_DIR}/3.edit/SysGraphic_png); do 46 | echo $inname 47 | python -B ${SRC_DIR}/advhd_pna.py i \ 48 | ${WORK_DIR}/3.edit/SysGraphic_png/$inname \ 49 | ${WORK_DIR}/2.pre/SysGraphic/$inname.pna \ 50 | ${WORK_DIR}/4.post/SysGraphic/$inname.pna 51 | done 52 | } 53 | 54 | build_3arcv2() { 55 | echo "## build_3arcv2" 56 | arcs=$(find ${WORK_DIR}/1.origin -type f -name *.arc -exec basename -s .arc {} \;|sort) 57 | for arc in $arcs; do 58 | echo $arc 59 | python -B ${SRC_DIR}/advhd_arcv2.py b \ 60 | ${WORK_DIR}/4.post/$arc \ 61 | ${WORK_DIR}/5.result/override/$arc.arc 62 | done 63 | } 64 | 65 | build_4dll() { 66 | echo "## build_4dll" 67 | if [ -n "$(uname -a | grep Linux)" ]; then 68 | if [ -z "$CC" ]; then CC=i686-w64-mingw32-gcc; fi 69 | else 70 | if [ -z "$CC" ]; then CC=clang; fi 71 | fi 72 | make -C ${SRC_DIR}/../ -f advhd.mk CC=$CC BUILD_DIR=${WORK_DIR}/5.result DEBUG=$DEBUG 73 | } 74 | 75 | build_4exe() { 76 | echo "## build_4exe" 77 | python -B ${SRC_DIR}/compat/windllin_v321.py -m codecave2 \ 78 | ${WORK_DIR}/1.origin/AdvHD.exe advhd_patch.dll \ 79 | -o ${WORK_DIR}/5.result/AdvHD_chs.exe 1>/dev/null 80 | 81 | echo "AdvHD_chs.exe | tee advhd_patch.log" > "${WORK_DIR}/5.result/AdvHD_chs_debug.cmd" 82 | 83 | # echo -e should be used in bash 84 | echo "codepage=936" > ${WORK_DIR}/5.result/override/config.ini 85 | echo "charset=134" >> ${WORK_DIR}/5.result/override/config.ini 86 | echo -e "font=\xce\xa2\xc8\xed\xd1\xc5\xba\xda" >> ${WORK_DIR}/5.result/override/config.ini 87 | echo "ucharmap=38021:9834" >> ${WORK_DIR}/5.result/override/config.ini 88 | } 89 | 90 | release_patch() { 91 | echo "## release_patch"W 92 | RELEASE_NAME="[$(date +"%y%m%d")build][vndb-v17853]BlackishHouse_${VERSION}[1CHSPATCH]" 93 | RELEASE_FILE=${WORK_DIR}/$RELEASE_NAME.7z 94 | RELEASE_DIR=${WORK_DIR}/5.result 95 | echo $RELEASE_NAME 96 | 7z a -mx5 $RELEASE_FILE $RELEASE_DIR 97 | 7z rn $RELEASE_FILE $(basename $RELEASE_DIR) $RELEASE_NAME 98 | } 99 | 100 | $* -------------------------------------------------------------------------------- /project/azsystem/lamune.mk: -------------------------------------------------------------------------------- 1 | # as the inline asm, only clang and msvc are supported 2 | CC:=clang 3 | BUILD_DIR:=asset/build 4 | SRC_DIR:=src 5 | INCS:=-I$(SRC_DIR)/compat 6 | LIBDIRS:=-L$(SRC_DIR)/compat 7 | LIBS:=-luser32 -lgdi32 -lshlwapi 8 | CFLAGS:=-ffunction-sections -fdata-sections -DUSE_COMPAT 9 | LDFLAGS:= 10 | 11 | ifdef DEBUG 12 | CFLAGS+=-g -D_DEBUG 13 | else 14 | CFLAGS+=-Os 15 | endif 16 | 17 | ifneq (,$(findstring clang, $(CC))) 18 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 19 | LDFLAGS+=-Wl,/OPT:REF 20 | else 21 | CFLAGS+=-m32 22 | ifneq (,$(findstring gcc, $(CC))) 23 | LDFLAGS+= -Wl,--gc-sections\ 24 | -static-libgcc -static-libstdc++ \ 25 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 26 | -Wl,--no-whole-archive 27 | endif 28 | endif 29 | 30 | all: lamune_patch 31 | 32 | lamune_patch: $(SRC_DIR)/lamune_patch.c 33 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 34 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 35 | rm -rf $(BUILD_DIR)/$@.exp 36 | rm -rf $(BUILD_DIR)/$@.lib 37 | rm -rf $(BUILD_DIR)/$@.def 38 | 39 | .PHONY: lamune_patch -------------------------------------------------------------------------------- /project/bruns/src/bruns_decrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is for decrypt EENZ files, DustmaniaGrotesque tested 3 | v0.1, developed by devseed 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #pragma pack(1) 10 | struct decrypt_buf 11 | { 12 | DWORD unkown1; 13 | char *bufstart; 14 | char *bufend; 15 | char *bufend2; 16 | }; 17 | 18 | struct wstring 19 | { 20 | size_t capability; 21 | union //0x4 22 | { 23 | wchar_t *extern_buf; 24 | wchar_t buf[10]; 25 | }; 26 | size_t capability2; // 0x18 27 | }; 28 | 29 | typedef int(*file_to_bytearray_nosearch)(struct decrypt_buf* a1, struct wstring* a2); 30 | 31 | void bruns_decrypt(char* inpath, char* outpath) 32 | { 33 | wchar_t inpathw[256] = {0}; 34 | mbstowcs(inpathw, inpath, 256); 35 | 36 | struct decrypt_buf a1 = {0}; 37 | struct wstring a2 ={0}; 38 | a2.capability = 0x190; 39 | a2.extern_buf = inpathw; 40 | a2.capability2 = 0x17; 41 | 42 | HMODULE hMod = LoadLibraryA("libscr.dll"); 43 | if(!hMod) 44 | { 45 | printf("error: can not load libscr.dll\n"); 46 | return; 47 | } 48 | file_to_bytearray_nosearch pfunc = (file_to_bytearray_nosearch)GetProcAddress(hMod, 49 | "?file_to_bytearray_nosearch@SepterEnv@@SA_NAAV?$vector_mtus@E@@ABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@Z"); 50 | if(!pfunc) 51 | { 52 | printf("error: can not find file_to_bytearray_nosearch\n"); 53 | return; 54 | } 55 | pfunc(&a1, &a2); 56 | if(a1.bufstart && a1.bufend-a1.bufstart>0) 57 | { 58 | FILE* fp = fopen(outpath, "wb"); 59 | size_t size = a1.bufend-a1.bufstart; 60 | fwrite(a1.bufstart, 1, size, fp); 61 | printf("%x bytes decrypted to %s!\n", size, outpath); 62 | fclose(fp); 63 | } 64 | FreeLibrary(hMod); 65 | } 66 | 67 | int main(int argc, char** argv) 68 | { 69 | if(argc<2) 70 | { 71 | printf("bruns_decrypt input [output]\n"); 72 | return 0; 73 | } 74 | char outpath[256]; 75 | if(argc>2) 76 | { 77 | strcpy(outpath, argv[2]); 78 | } 79 | else 80 | { 81 | strcpy(outpath, argv[1]); 82 | strcat(outpath, ".txt"); 83 | } 84 | bruns_decrypt(argv[1], outpath); 85 | return 0; 86 | } -------------------------------------------------------------------------------- /project/criware/iwaihime.mk: -------------------------------------------------------------------------------- 1 | # make -f krkrtool.mk CC=/opt/llvm-mingw/bin/i686-w64-mingw32-clang++ # llvm 18.1.8 2 | # make -f krkrtool.mk CC=i686-w64-mingw32-gcc++ # gcc 12 3 | 4 | CC:=clang 5 | BUILD_DIR:=asset/build 6 | INCS:=-Isrc/compat 7 | LIBS:=-luser32 -lgdi32 -lshlwapi -ladvapi32 8 | CFLAGS:=-ffunction-sections -fdata-sections -Wno-null-dereference 9 | LDFLAGS:= 10 | 11 | ifdef DEBUG 12 | CFLAGS+=-g -D_DEBUG 13 | else 14 | CFLAGS+=-Os 15 | endif 16 | ifneq (,$(wildcard src/compat/*)) 17 | CFLAGS+=-DUSECOMPAT 18 | endif 19 | 20 | ifneq (,$(findstring clang, $(CC))) # for llvm-mingw 21 | CFLAGS+=-m32 \ 22 | -Wl,-Bstatic,--whole-archive -lunwind \ 23 | -Wl,--no-whole-archive \ 24 | -gcodeview -Wl,--pdb=$(BUILD_DIR)/version.pdb 25 | LDFLAGS+= -Wl,--gc-sections 26 | else ifneq (,$(findstring gcc, $(CC))) # for mingw-w64 27 | CFLAGS+=-m32 28 | LDFLAGS+= -Wl,--gc-sections \ 29 | -static-libgcc \ 30 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 31 | -Wl,--no-whole-archive 32 | else ifneq (,$(findstring tcc, $(CC))) # for tcc 33 | CFLAGS+=-m32 34 | else # for previous llvm clang with msvc 35 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 36 | LDFLAGS+=-Wl,/OPT:REF # for llvm 37 | endif 38 | 39 | all: prepare iwaihime_sn iwaihime_patch 40 | 41 | prepare: 42 | @mkdir -p $(BUILD_DIR) 43 | 44 | iwaihime_sn: src/iwaihime_sn.c 45 | @echo "## $@" 46 | $(CC) $^ -o$(BUILD_DIR)/$@.exe \ 47 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 48 | @if [ -f $(BUILD_DIR)/version.pdb ]; then cp -f $(BUILD_DIR)/version.pdb $(BUILD_DIR)/$@.pdb; fi 49 | @rm -rf $(BUILD_DIR)/version.* 50 | 51 | iwaihime_patch: src/iwaihime_patch.c src/compat/winversion_v100.def 52 | @echo "## $@" 53 | $(CC) -shared $^ -o$(BUILD_DIR)/version.dll \ 54 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 55 | @cp -f $(BUILD_DIR)/version.dll $(BUILD_DIR)/$@.dll 56 | @if [ -f $(BUILD_DIR)/version.pdb ]; then cp -f $(BUILD_DIR)/version.pdb $(BUILD_DIR)/$@.pdb; fi 57 | @rm -rf $(BUILD_DIR)/version.* 58 | 59 | .PHONY: prepare iwaihime_sn iwaihime_patch -------------------------------------------------------------------------------- /project/criware/src/compat/winversion_v100.def: -------------------------------------------------------------------------------- 1 | LIBRARY "version" 2 | EXPORTS 3 | GetFileVersionInfoA = __wrap_GetFileVersionInfoA 4 | GetFileVersionInfoByHandle = __wrap_GetFileVersionInfoByHandle 5 | GetFileVersionInfoExA = __wrap_GetFileVersionInfoExA 6 | GetFileVersionInfoExW = __wrap_GetFileVersionInfoExW 7 | GetFileVersionInfoSizeA = __wrap_GetFileVersionInfoSizeA 8 | GetFileVersionInfoSizeExA = __wrap_GetFileVersionInfoSizeExA 9 | GetFileVersionInfoSizeExW = __wrap_GetFileVersionInfoSizeExW 10 | GetFileVersionInfoSizeW = __wrap_GetFileVersionInfoSizeW 11 | GetFileVersionInfoW = __wrap_GetFileVersionInfoW 12 | VerFindFileA = __wrap_VerFindFileA 13 | VerFindFileW = __wrap_VerFindFileW 14 | VerInstallFileA = __wrap_VerInstallFileA 15 | VerInstallFileW = __wrap_VerInstallFileW 16 | VerLanguageNameA = __wrap_VerLanguageNameA 17 | VerLanguageNameW = __wrap_VerLanguageNameW 18 | VerQueryValueA = __wrap_VerQueryValueA 19 | VerQueryValueW = __wrap_VerQueryValueW -------------------------------------------------------------------------------- /project/criware/src/compat/winversion_v100.h: -------------------------------------------------------------------------------- 1 | /** 2 | * windows version dll proxy, together with winversion.def 3 | * v0.1, developed by devseed 4 | * 5 | */ 6 | 7 | #ifndef _WINVERSION_H 8 | #define _WINVERSION_H 9 | #include 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | #define WIVERSION_VERSION 100 14 | 15 | #ifdef USECOMPAT 16 | #include "commdef_v110.h" 17 | #else 18 | #include "commdef.h" 19 | #endif // USECOMPAT 20 | 21 | // macro and global declear 22 | static HMODULE s_winversion = NULL; 23 | #if defined(_MSC_VER) 24 | // https://github.com/BitCrackers/version-proxy/blob/main/src/version.cpp 25 | #ifdef _M_AMD64 // msvc x64 26 | #pragma warning (disable: 4081) 27 | #define STRINGIFY(name) #name 28 | #define EXPORT_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) 29 | #define WINVERSION_WRAP_FUNC(name) \ 30 | FARPROC s_##name; \ 31 | __declspec(dllexport) void WINAPI __wrap_##name() \ 32 | { \ 33 | __pragma(STRINGIFY(EXPORT_FUNCTION)); \ 34 | s_##name(); \ 35 | } 36 | #else // msvc x86 37 | #define WINVERSION_WRAP_FUNC(name) \ 38 | static FARPROC s_##name; \ 39 | __declspec(naked) void __wrap_##name() \ 40 | { \ 41 | __asm jmp[s_##name] \ 42 | } 43 | #endif 44 | #else // gcc 45 | #define WINVERSION_WRAP_FUNC(name) \ 46 | static FARPROC s_##name = NULL; \ 47 | EXPORT NAKED void __wrap_##name () \ 48 | {\ 49 | asm volatile("jmp *%0" : : "m" (s_##name)); \ 50 | } 51 | 52 | #endif // _MSC_VER 53 | #define WINVERSION_BIND_FUNC(name) s_##name = GetProcAddress(s_winversion, #name); 54 | 55 | // export function define 56 | WINVERSION_WRAP_FUNC(GetFileVersionInfoA) 57 | WINVERSION_WRAP_FUNC(GetFileVersionInfoByHandle) 58 | WINVERSION_WRAP_FUNC(GetFileVersionInfoExW) 59 | WINVERSION_WRAP_FUNC(GetFileVersionInfoExA) 60 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeA) 61 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeExW) 62 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeExA) 63 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeW) 64 | WINVERSION_WRAP_FUNC(GetFileVersionInfoW) 65 | WINVERSION_WRAP_FUNC(VerFindFileA) 66 | WINVERSION_WRAP_FUNC(VerFindFileW) 67 | WINVERSION_WRAP_FUNC(VerInstallFileA) 68 | WINVERSION_WRAP_FUNC(VerInstallFileW) 69 | WINVERSION_WRAP_FUNC(VerLanguageNameA) 70 | WINVERSION_WRAP_FUNC(VerLanguageNameW) 71 | WINVERSION_WRAP_FUNC(VerQueryValueA) 72 | WINVERSION_WRAP_FUNC(VerQueryValueW) 73 | 74 | static void winversion_init() 75 | { 76 | // origin version path 77 | char versionpath[MAX_PATH]; 78 | GetSystemDirectoryA(versionpath, MAX_PATH); 79 | strcat(versionpath, "\\version.dll"); 80 | s_winversion = LoadLibraryA(versionpath); 81 | 82 | // bind version apis 83 | WINVERSION_BIND_FUNC(GetFileVersionInfoA); 84 | WINVERSION_BIND_FUNC(GetFileVersionInfoByHandle); 85 | WINVERSION_BIND_FUNC(GetFileVersionInfoExW); 86 | WINVERSION_BIND_FUNC(GetFileVersionInfoExA); 87 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeA); 88 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeExW); 89 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeExA); 90 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeW); 91 | WINVERSION_BIND_FUNC(GetFileVersionInfoW); 92 | WINVERSION_BIND_FUNC(VerFindFileA); 93 | WINVERSION_BIND_FUNC(VerFindFileW); 94 | WINVERSION_BIND_FUNC(VerInstallFileA); 95 | WINVERSION_BIND_FUNC(VerInstallFileW); 96 | WINVERSION_BIND_FUNC(VerLanguageNameA); 97 | WINVERSION_BIND_FUNC(VerLanguageNameW); 98 | WINVERSION_BIND_FUNC(VerQueryValueA); 99 | WINVERSION_BIND_FUNC(VerQueryValueW); 100 | } 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | #endif -------------------------------------------------------------------------------- /project/criware/src/iwaihime_font.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | make xtx format font for iwaihime (font48.xtx) 5 | v0.1, developed by devseed 6 | """ 7 | 8 | import os 9 | import sys 10 | import struct 11 | import xtx_font 12 | 13 | sys.path.append(os.path.join(os.path.dirname(__file__), r"compat")) 14 | try: 15 | import compat.libfont_v180 as futil 16 | except ImportError as e: 17 | pass 18 | 19 | width = 6144 20 | height = 3072 21 | char_width = 48 22 | char_height = 48 23 | charcount = 8192 24 | 25 | def generate_gb2312_tbl(): 26 | pass 27 | 28 | def generate_sjis_tbl(): 29 | tbl = [] 30 | for high in range(0x81, 0xa0): 31 | for low in range(0x40, 0xfd): 32 | if low == 0x7f: continue 33 | charcode = struct.pack(' ", rebuild) 29 | return data_boot 30 | 31 | def debug(): 32 | pass 33 | 34 | def main(): 35 | if len(sys.argv) < 3: 36 | print("baranoki_psp_boot f bootpath orgafsdir rebuildafsdir outpath") 37 | return 38 | 39 | if sys.argv[1] == 'f': 40 | orgbootpath = sys.argv[2] 41 | orgafsdir = sys.argv[3] 42 | rebuildafsdir = sys.argv[4] 43 | rebuildbootpath = sys.argv[5] 44 | 45 | with open(orgbootpath, 'rb') as fp: 46 | data_boot = bytearray(fp.read()) 47 | data_boot = rebuild_filesize_table(data_boot, orgafsdir, rebuildafsdir) 48 | with open(rebuildbootpath, 'wb') as fp: 49 | fp.write(data_boot) 50 | 51 | else: raise ValueError(f"not support option {sys.argv[1]}") 52 | 53 | pass 54 | 55 | if __name__ == "__main__": 56 | main() 57 | pass -------------------------------------------------------------------------------- /project/cycrose/src/baranoki_psp_pktext.py: -------------------------------------------------------------------------------- 1 | """ 2 | for BaranoKiniBaranoSaku psp 3 | this is for import the text with sjis @filename, in .pk files 4 | v0.1, developed by devseed 5 | """ 6 | 7 | import os 8 | import sys 9 | from io import BytesIO 10 | 11 | sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), r"compat")) 12 | import bintext_v440 as bintext 13 | 14 | def insert_pktext(pkpath, textpath, tblpath, outpath="out"): 15 | with open(pkpath, 'rb') as fp: 16 | data = bytearray(fp.read()) 17 | _, ftexts2 = bintext.read_format_text(textpath) 18 | tbl = bintext.load_tbl(tblpath) 19 | for ftext in ftexts2: 20 | addr,text,size = ftext['addr'],ftext['text'],ftext['size'] 21 | fileflag = False 22 | buf = BytesIO() 23 | for c in text: 24 | if c=='@': 25 | fileflag = True 26 | buf.write(b'@') 27 | continue 28 | if c == ' ': 29 | fileflag = False 30 | buf.write(b' ') 31 | continue 32 | 33 | if fileflag: charcode = c.encode('sjis') 34 | else: charcode = bintext.encode_tbl(c, tbl) 35 | buf.write(charcode) 36 | 37 | buf = bytearray(buf.getbuffer()) 38 | if len(buf) <= size: 39 | data[addr:addr+len(buf)] = buf 40 | data[addr+len(buf): addr+size] = (size-len(buf)) * b' ' 41 | else: 42 | print("%x, %d > %d"%(addr, len(buf), size)) 43 | 44 | with open(outpath, 'wb') as fp: 45 | fp.write(data) 46 | 47 | def debug(): 48 | pass 49 | 50 | def main(): 51 | if len(sys.argv) < 5: 52 | print("pktext i pkpath textpath tblpath [outpath]") 53 | return 54 | 55 | outpath = sys.argv[5] if len(sys.argv)>5 else "./out" 56 | if sys.argv[1].lower() == 'i': 57 | insert_pktext(sys.argv[2], sys.argv[3], sys.argv[4], outpath) 58 | else: 59 | print("Invalid argument,", sys.argv[1]) 60 | 61 | if __name__ == "__main__": 62 | #debug() 63 | main() 64 | pass -------------------------------------------------------------------------------- /project/cycrose/src/baranoki_psp_zp.py: -------------------------------------------------------------------------------- 1 | """ 2 | for BaranoKiniBaranoSaku psp, 3 | decode and encode zp format, 4 | v0.1, developed by devseed 5 | """ 6 | import gzip 7 | import os 8 | import sys 9 | from io import BytesIO 10 | 11 | def uncompress_zp(inpath, outdir): 12 | with open(inpath, 'rb') as fp: 13 | fp.seek(0xa) 14 | s = bytearray() 15 | while True: 16 | c = fp.read(1) 17 | if c==b'\x00': break 18 | s += c 19 | name = s.decode('utf-8') 20 | with gzip.open(inpath, 'rb') as fp: 21 | data = fp.read() 22 | outpath = os.path.join(outdir, name) 23 | print(name, "uncompressed") 24 | with open(outpath, 'wb') as fp: 25 | fp.write(data) 26 | 27 | def compress_zp(inpath, outdir="", *, compresslevel=1, extra_flag=4): 28 | # making gzip with filename 29 | name = inpath.split('\\')[-1] 30 | with open(inpath, 'rb') as fp: 31 | data = fp.read() 32 | data_zp = BytesIO() 33 | fp_zp = gzip.GzipFile(name.encode('utf-8'), mode = 'wb', fileobj=data_zp, compresslevel=compresslevel) 34 | fp_zp.write(data) 35 | fp_zp.close() 36 | 37 | # header fix 38 | data_zp.getbuffer()[0x8] = extra_flag # XFL = 4 - compressor used fastest algorithm 39 | data_zp.getbuffer()[0x9] = 0x3 # unix 40 | if outdir!="": 41 | outpath = os.path.join(outdir, name+'.zp') 42 | with open(outpath, 'wb') as fp: 43 | fp.write(data_zp.getbuffer()) 44 | print(name, hex(len(data_zp.getbuffer())), "bytes compressed!") 45 | return data_zp.getbuffer() 46 | 47 | def debug(): 48 | uncompress_zp(r"D:\Make\Reverse\BaranoKini_psp\test\付録.gim_org.zp", r"D:\MAKE\Reverse\BaranoKini_psp\intermediate") 49 | 50 | def main(): 51 | if len(sys.argv) < 2: 52 | print("zp d inpath(indir) [outdir]") 53 | print("zp e inpath(indir) [outdir]") 54 | 55 | if sys.argv[1].lower() == 'd': 56 | func = uncompress_zp 57 | elif sys.argv[1].lower() == 'e': 58 | func = compress_zp 59 | else: print("invalid argument") 60 | inpath = sys.argv[2] 61 | if len(sys.argv) >= 4: 62 | outdir = sys.argv[3] 63 | else: 64 | if os.path.isdir(inpath): outdir = inpath 65 | else: outdir = os.path.dirname(inpath) 66 | 67 | if not os.path.exists(outdir): os.makedirs(outdir) 68 | if os.path.isfile(inpath): 69 | func(inpath, outdir) 70 | else: 71 | indir = inpath 72 | for file in os.listdir(inpath): 73 | inpath = os.path.join(indir, file) 74 | try: 75 | func(inpath, outdir) 76 | except: 77 | print(inpath + " error") 78 | 79 | if __name__ == "__main__": 80 | #debug() 81 | main() 82 | pass -------------------------------------------------------------------------------- /project/eldia/make_libkanda_fontmap.bat: -------------------------------------------------------------------------------- 1 | if %DEVKITPRO%=="" ( 2 | set DEVKITPRO=d:\Software\env\sdk\switchsdk 3 | ) 4 | set PATH=%PATH%;%DEVKITPRO%\tools\bin;%DEVKITPRO%\devkitA64\bin 5 | aarch64-none-elf-gcc src/kanda_switch_fontmap.c -nostdlib -nodefaultlibs -fPIC -shared -o asset/build/libkanda_fontmap.so -Os -------------------------------------------------------------------------------- /project/eldia/src/kanda_switch_fontmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | build the ConvertGb2312ToUtf16 arm64 binray code to support gb2312 3 | v0.1, developed by devseed 4 | */ 5 | 6 | #include 7 | #include 8 | #ifdef _DEBUG 9 | #include 10 | #endif 11 | 12 | #define FONTMAP_ADDR 0x710014AE98 13 | #define FONTMAP_OFFSET_TO_LR (FONTMAP_ADDR-0x710000CB04) 14 | 15 | int ConvertUtf16ToUtf16(uint16_t* unicode_buf, int unicode_bufsize, const unsigned char* multibye_buf) //this not be worked, becuase script asci 16 | { 17 | int i=0; 18 | while(multibye_buf[i] || multibye_buf[i+1]) 19 | { 20 | if(i>unicode_bufsize) return 1; 21 | unicode_buf[i/2] = multibye_buf[i] + (multibye_buf[i+1]<<8&0xff00); 22 | i +=2; 23 | } 24 | return 0; 25 | } 26 | 27 | int ConvertGb2312ToUtf16(uint16_t* unicode_buf, int unicode_bufsize, const unsigned char* multibye_buf) 28 | { 29 | int unicode_idx = 0; 30 | int multibyte_idx = 0; 31 | register uint16_t* fontmap = 0; 32 | // because only one position invoke this function, can use LR 33 | __asm__ __volatile__ ("mov %0, lr;" : "=r"(fontmap)); 34 | fontmap = (uint16_t*)((uint64_t)fontmap + FONTMAP_OFFSET_TO_LR); 35 | 36 | while(multibye_buf[multibyte_idx]) 37 | { 38 | if(unicode_idx>unicode_bufsize) return 1; 39 | if(multibye_buf[multibyte_idx] < 0x7f) // 1byte asci 40 | { 41 | unicode_buf[unicode_idx++] = multibye_buf[multibyte_idx++]; 42 | continue; 43 | } 44 | 45 | unsigned char first_byte = multibye_buf[multibyte_idx++]; 46 | if(first_byte>=0xa1 && first_byte<=0xfe) 47 | { 48 | unsigned char second_byte = multibye_buf[multibyte_idx++]; 49 | if(second_byte>=0xa1 && second_byte<=0xfe) 50 | { 51 | // fontmap is big-endian 52 | unicode_buf[unicode_idx++] = fontmap[(second_byte-0xa1)+(first_byte-0xa1)*(0xff-0xa1)]; 53 | } 54 | else 55 | { 56 | multibyte_idx+=2; 57 | unicode_buf[unicode_idx++] = fontmap[1]; 58 | //return 2; 59 | } 60 | } 61 | else 62 | { 63 | multibyte_idx+=2; 64 | unicode_buf[unicode_idx++] = fontmap[1]; 65 | //return 2; 66 | } 67 | } 68 | return 0; 69 | } 70 | 71 | int FONT_IsJIS(unsigned char a1) // seems not used 72 | { 73 | if(a1>=0x81 && a1<=0xfe) return 1; 74 | else return 0; 75 | } 76 | 77 | int ReadNextCharSjis(void* this) // seems not used 78 | { 79 | unsigned char *pcur = (unsigned char *)this; 80 | int result=0; 81 | if(*pcur<0x80) 82 | { 83 | result = *pcur; 84 | pcur += 1; 85 | } 86 | else 87 | { 88 | result = ((*pcur<<8)&0xff00)+*(pcur+1); 89 | pcur += 2; 90 | } 91 | return result; 92 | } 93 | 94 | #ifdef _DEBUG 95 | int main(int argc, char** argv) 96 | { 97 | char *str = "\x4b\x6d\xd5\x8b"; 98 | wchar_t wstr[100] = {0}; 99 | ConvertUtf16ToUtf16(wstr, 4, str); 100 | wprintf(L"%ls\n", wstr); 101 | return 0; 102 | } 103 | #endif -------------------------------------------------------------------------------- /project/eldia/src/kanda_switch_fontmap.py: -------------------------------------------------------------------------------- 1 | """ 2 | make the fontmap to gb2312 and patch sjis char check 3 | tested in Kanda Alice switch version, 4 | v0.1 developed by devseed 5 | """ 6 | 7 | import os 8 | import sys 9 | import struct 10 | import mmap 11 | import lief 12 | from keystone import Ks, KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN 13 | 14 | # offset for main v1.01 15 | g_fontmap_offset = 0x14aac9 16 | g_fontmap_length = 9400*2 17 | g_sjistoutf16_offset = 0x6b31 18 | g_FontIsSjis_offset = 0xc721 # 08 1C 00 13 not use 19 | g_ReadNextCharSjis_offset = 0x99431 # 09 00 40 F9 28 01 40 39 not 20 | g_FONT_GetSjisByMapUV = 0xa691 # E9 03 1F AA E8 80 10 B0 not use 21 | 22 | def generate_gb2312_tbl_full(): 23 | tbl = [] 24 | for high in range(0xa1, 0xff): # Chinese charactor 25 | for low in range(0xa1, 0xff): 26 | charcode = struct.pack('=len(tbl): break 91 | wchars[i] = tbl[i][1] 92 | return write_unicode_map(data, fontmap_offset, wchars) 93 | 94 | def rebuild_main_func(libpath, func_name, data, offset): 95 | code = get_func_code(libpath, func_name) 96 | patch_code(data, offset, code) 97 | print([hex(x) for x in list(code)]) 98 | print("Func %s injected %d bytes to %x,"%(func_name,len(code), offset)) 99 | 100 | def rebuild_main(mainpath, libpath, outpath): 101 | fd = os.open(mainpath, os.O_RDONLY) 102 | data = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) 103 | 104 | # rebuild fontmap 105 | tbl = generate_gb2312_tbl_full() 106 | data2 = rebuild_main_fontmap(data, tbl,g_fontmap_offset, g_fontmap_length) 107 | 108 | # rebuild functions 109 | rebuild_main_func(libpath, "ConvertGb2312ToUtf16", data2, g_sjistoutf16_offset) 110 | patch_sjis_check(data2) 111 | 112 | with open(outpath, 'wb') as fp: 113 | fp.write(data2) 114 | print("save rebuild main to", outpath) 115 | os.close(fd) 116 | pass 117 | 118 | def debug(): 119 | rebuild_main(r"./build/intermediate/origin/main_v1.01", 120 | r"./build/libkanda_fontmap.so", r"./build/main") 121 | pass 122 | 123 | def main(): 124 | if len(sys.argv) < 4: 125 | print("kanda_fontmap main libkanda_fontmap main_rebuild") 126 | return 127 | rebuild_main(sys.argv[1], sys.argv[2], sys.argv[3]) 128 | 129 | if __name__ =="__main__": 130 | #debug() 131 | main() 132 | pass -------------------------------------------------------------------------------- /project/exhibit/soraironoorgan.mk: -------------------------------------------------------------------------------- 1 | # as the inline asm, only clang and msvc are supported 2 | CC:=clang 3 | BUILD_DIR:=./asset/build 4 | INCS:=-I./src/compat 5 | LIBDIRS:=-L./src/compat 6 | LIBS:=-luser32 -lgdi32 -lshlwapi 7 | CFLAGS:=-ffunction-sections -fdata-sections 8 | LDFLAGS:= 9 | 10 | ifdef DEBUG 11 | CFLAGS+=-g -D_DEBUG 12 | else 13 | CFLAGS+=-Os 14 | endif 15 | 16 | ifneq (,$(findstring clang, $(CC))) 17 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 18 | LDFLAGS+=-Wl,/OPT:REF 19 | else 20 | CFLAGS+=-m32 21 | ifneq (,$(findstring gcc, $(CC))) 22 | LDFLAGS+= -Wl,--gc-sections\ 23 | -static-libgcc -static-libstdc++ \ 24 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 25 | -Wl,--no-whole-archive 26 | endif 27 | endif 28 | 29 | all: soraironoorgan_patch 30 | 31 | soraironoorgan_patch: src/soraironoorgan_patch.c 32 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll -D USE_COMPAT \ 33 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 34 | rm -rf $(BUILD_DIR)/$@.exp 35 | rm -rf $(BUILD_DIR)/$@.lib 36 | 37 | .PHONY: soraironoorgan_patch -------------------------------------------------------------------------------- /project/exhibit/src/soraironoorgan_patch.c: -------------------------------------------------------------------------------- 1 | /** 2 | * for SorairoNoOrgan chs support 3 | * v0.1, developed by devseed 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #define WINHOOK_IMPLEMENTATION 11 | #define WINHOOK_NOINLINEHOOK 12 | #ifdef USE_COMPAT 13 | #include "winhook_v310.h" 14 | #else 15 | #include "winhook.h" 16 | #endif 17 | 18 | HMODULE WINAPI LoadLibraryExA_hook( 19 | LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) 20 | { 21 | printf("LoadLibraryExA %s\n", lpLibFileName); 22 | if(strstr(lpLibFileName, "sc00.dll")) 23 | { 24 | strcpy((char*)lpLibFileName, "sc00.dll"); 25 | } 26 | return LoadLibraryExA(lpLibFileName, hFile, dwFlags); 27 | } 28 | 29 | LPSTR WINAPI CharNextA_hook(LPCSTR lpsz) 30 | { 31 | if ((*((unsigned char*)lpsz)) < 0x80) 32 | return CharNextA(lpsz); 33 | else return (LPSTR)(lpsz+2); 34 | } 35 | 36 | HFONT WINAPI CreateFontIndirectA_hook(LOGFONTA *lplf) 37 | { 38 | //printf("in CreateFontIndirectA_hook\n"); 39 | lplf->lfCharSet = GB2312_CHARSET; 40 | strcpy(lplf->lfFaceName, "simhei"); 41 | return CreateFontIndirectA(lplf); 42 | } 43 | 44 | int WINAPI MultiByteToWideChar_hook( 45 | UINT CodePage, DWORD dwFlags, 46 | LPCCH lpMultiByteStr, int cbMultiByte, 47 | LPWSTR lpWideCharStr, int cchWideChar 48 | ) 49 | { 50 | return MultiByteToWideChar(CodePage, 51 | dwFlags, lpMultiByteStr, cbMultiByte, 52 | lpWideCharStr, cchWideChar); 53 | } 54 | 55 | void install_residenthook() 56 | { 57 | if(!LoadLibraryA("resident.dll")) 58 | { 59 | MessageBoxA(NULL, "load resident.dll failed!", "error", 0); 60 | } 61 | if(!winhook_iathookmodule("User32.dll", "resident.dll", 62 | GetProcAddress(GetModuleHandleA("user32.dll"), 63 | "CharNextA"), (PROC)CharNextA_hook)) 64 | { 65 | MessageBoxA(NULL, "iathook resident.dll CharNextA failed!", "error", 0); 66 | } 67 | if(!winhook_iathookmodule("gdi32.dll", "resident.dll", 68 | GetProcAddress(GetModuleHandleA("gdi32.dll"), 69 | "CreateFontIndirectA"), (PROC)CreateFontIndirectA_hook)) 70 | { 71 | MessageBoxA(NULL, "iathook resident.dll CreateFontIndirectA failed!", "error", 0); 72 | } 73 | printf("install_residenthook finished!\n"); 74 | } 75 | 76 | void install_schook() 77 | { 78 | if(!LoadLibraryA("sc00.dll")) 79 | { 80 | MessageBoxA(NULL, "load sc00.dll failed!", "error", 0); 81 | } 82 | if(!winhook_iathookmodule("Kernel32.dll", "sc00.dll", 83 | GetProcAddress(GetModuleHandleA("Kernel32.dll"), 84 | "MultiByteToWideChar"), (PROC)MultiByteToWideChar_hook)) 85 | { 86 | MessageBoxA(NULL, "iathook sc00.dll MultiByteToWideChar failed!", "error", 0); 87 | } 88 | if(!winhook_iathookmodule("User32.dll", "sc00.dll", 89 | GetProcAddress(GetModuleHandleA("user32.dll"), 90 | "CharNextA"), (PROC)CharNextA_hook)) 91 | { 92 | MessageBoxA(NULL, "iathook sc00.dll CharNextA failed!", "error", 0); 93 | } 94 | if(!winhook_iathookmodule("gdi32.dll", "sc00.dll", 95 | GetProcAddress(GetModuleHandleA("gdi32.dll"), 96 | "CreateFontIndirectA"), (PROC)CreateFontIndirectA_hook)) 97 | { 98 | MessageBoxA(NULL, "iathook sc00.dll CreateFontIndirectA failed!", "error", 0); 99 | } 100 | printf("install_schook finished!\n"); 101 | } 102 | 103 | void install_exehook() 104 | { 105 | if(!winhook_iathook("Kernel32.dll", 106 | GetProcAddress(GetModuleHandleA("Kernel32.dll"), 107 | "LoadLibraryExA"), (PROC)LoadLibraryExA_hook)) 108 | { 109 | MessageBoxA(NULL, "iathook LoadLibraryExA failed!", "error", 0); 110 | } 111 | printf("install_exehook finished!\n"); 112 | } 113 | 114 | void install_hooks() 115 | { 116 | #ifdef _DEBUG 117 | AllocConsole(); 118 | //MessageBoxA(0, "debug install", "debug", 0); 119 | freopen("CONOUT$", "w", stdout); 120 | printf("sorairo_patch, v0.1, build in 220607\n"); 121 | #endif 122 | install_exehook(); 123 | install_residenthook(); 124 | install_schook(); 125 | } 126 | 127 | BOOL WINAPI DllMain( 128 | HINSTANCE hinstDLL, // handle to DLL module 129 | DWORD fdwReason, // reason for calling function 130 | LPVOID lpReserved ) // reserved 131 | { 132 | switch( fdwReason ) 133 | { 134 | case DLL_PROCESS_ATTACH: 135 | install_hooks(); 136 | break; 137 | case DLL_THREAD_ATTACH: 138 | break; 139 | case DLL_THREAD_DETACH: 140 | break; 141 | case DLL_PROCESS_DETACH: 142 | break; 143 | } 144 | return TRUE; 145 | } -------------------------------------------------------------------------------- /project/ffa/amanomiko.mk: -------------------------------------------------------------------------------- 1 | # as the inline asm, only clang and msvc are supported 2 | CC:=clang 3 | BUILD_DIR:=./asset/build 4 | INCS:=-Isrc/compat 5 | LIBDIRS:=-Lsrc/compat 6 | LIBS:=-luser32 -lgdi32 -lshlwapi 7 | CFLAGS:=-ffunction-sections -fdata-sections 8 | LDFLAGS:= 9 | 10 | ifdef DEBUG 11 | CFLAGS+=-g -D_DEBUG 12 | else 13 | CFLAGS+=-Os 14 | endif 15 | 16 | ifdef USE_DVFS 17 | CFLAGS+=-DUSE_DVFS 18 | endif 19 | 20 | CFLAGS64:=$(CFLAGS) 21 | ifneq (,$(findstring clang, $(CC))) 22 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 23 | CFLAGS64+=-target x86_64-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 24 | LDFLAGS+=-Wl,/OPT:REF 25 | else 26 | CFLAGS+=-m32 27 | CFLAGS64+=-m64 28 | ifneq (,$(findstring gcc, $(CC))) 29 | LDFLAGS+= -Wl,--gc-sections\ 30 | -static-libgcc -static-libstdc++ \ 31 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 32 | -Wl,--no-whole-archive 33 | endif 34 | endif 35 | 36 | all: amanomiko_patch 37 | 38 | amanomiko_patch: src/amanomiko_patch.c 39 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 40 | -DUSE_COMPAT \ 41 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 42 | rm -rf $(BUILD_DIR)/$@.exp 43 | rm -rf $(BUILD_DIR)/$@.lib 44 | 45 | liblzss20_64: src/liblzss20.c 46 | $(CC) -shared $^ -o src/$@.dll \ 47 | -DUSE_COMPAT \ 48 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS64) $(LDFLAGS) 49 | rm -rf src/$@.exp 50 | rm -rf src/$@.lib 51 | rm -rf src/$@.pdb 52 | 53 | .PHONY: amanomiko_patch liblzss20_64 -------------------------------------------------------------------------------- /project/ffa/src/amanomiko_install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set CURPATH=%~dp0 3 | ::reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\G1WIN.EXE" /d "%~dp0G1WIN.EXE" /f 4 | reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\G1WIN.EXE" /v "Path" /d "%CURPATH:~0,-1%" /f -------------------------------------------------------------------------------- /project/ffa/src/amanomiko_lzss.py: -------------------------------------------------------------------------------- 1 | """ 2 | parsing lzss compress file for for 天巫女姫, 3 | v0.1, developed by devseed 4 | 5 | """ 6 | 7 | import os 8 | import sys 9 | import mmap 10 | import struct 11 | from typing import Union 12 | from ctypes import CDLL, addressof, c_char, c_char_p, c_size_t 13 | 14 | try: 15 | g_lzmadll = CDLL(os.path.join(os.path.dirname(sys.argv[0]), "liblzss20_64.dll")) 16 | except FileNotFoundError as e: 17 | g_lzmadll = CDLL("./liblzss20_64.dll") 18 | 19 | g_lzmadll.lzss_encode.argtypes = [c_char_p, c_char_p, c_size_t] 20 | g_lzmadll.lzss_encode.restype = c_size_t 21 | g_lzmadll.lzss_decode.argtypes = [c_char_p, c_char_p, c_size_t] 22 | g_lzmadll.lzss_decode.restype = c_size_t 23 | 24 | def decode_lzss(inobj: Union[str, memoryview], outpath="out"): 25 | fd = None 26 | if type(inobj) == str: 27 | fd = os.open(inobj, os.O_RDWR) 28 | data = mmap.mmap(fd, 0) 29 | else: data = inobj 30 | 31 | zsize, rawsize = struct.unpack(" 3 else "out" 78 | if sys.argv[1].lower() == 'e': 79 | encode_lzss(sys.argv[2], outpath) 80 | elif sys.argv[1].lower() == 'd': 81 | decode_lzss(sys.argv[2], outpath) 82 | else: raise ValueError(f"unknow format {sys.argv[1]}") 83 | 84 | if __name__ == '__main__': 85 | # debug() 86 | main() 87 | pass -------------------------------------------------------------------------------- /project/ffa/src/amanomiko_patch.c: -------------------------------------------------------------------------------- 1 | /** 2 | * for G1WIN.EXE (天巫女姫) chs support 3 | * v0.1.1, developed by devseed 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // lzss v1.0 13 | #define LZSS_IMPLEMENTATION 14 | #define LZSS_DECINITBYTE 0x20 15 | #ifdef USE_COMPAT 16 | #include "lzss_v1000.h" 17 | #else 18 | #include "lzss.h" 19 | #endif 20 | 21 | #ifdef USE_DVFS 22 | #define WINDVFS_IMPLEMENTATION 23 | #ifdef USE_COMPAT 24 | #include "dvfs/windvfs_v301.h" 25 | #else 26 | #include "windvfs.h" 27 | #endif 28 | #else 29 | #define WINHOOK_IMPLEMENTATION 30 | #include "winhook_v310.h" 31 | #endif 32 | 33 | struct ffalzss_t{ 34 | uint32_t zsize; 35 | uint32_t rawsize; 36 | char data[1]; 37 | }; 38 | 39 | PVOID g_pfnTargets[]; 40 | PVOID g_pfnNews[]; 41 | PVOID g_pfnOlds[]; 42 | 43 | HFONT WINAPI CreateFontIndirectA_hook(LOGFONTA *lplf) 44 | { 45 | lplf->lfCharSet = GB2312_CHARSET; 46 | strcpy(lplf->lfFaceName, "simhei"); 47 | return CreateFontIndirectA(lplf); 48 | } 49 | 50 | int WINAPI WideCharToMultiByte_hook(UINT CodePage, DWORD dwFlags, 51 | LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, 52 | int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar 53 | ) 54 | { 55 | CodePage=936; 56 | return WideCharToMultiByte(CodePage, dwFlags, 57 | lpWideCharStr, cchWideChar, lpMultiByteStr, 58 | cbMultiByte, lpDefaultChar, lpUsedDefaultChar); 59 | } 60 | 61 | int WINAPI MultiByteToWideChar_hook( 62 | UINT CodePage, DWORD dwFlags, 63 | LPCCH lpMultiByteStr, int cbMultiByte, 64 | LPWSTR lpWideCharStr, int cchWideChar 65 | ) 66 | { 67 | CodePage=936; 68 | return MultiByteToWideChar(CodePage, dwFlags, 69 | lpMultiByteStr, cbMultiByte, 70 | lpWideCharStr, cchWideChar); 71 | } 72 | 73 | int __cdecl _ismbblead_hook(unsigned int Ch) 74 | { 75 | // typedef int (*PFN_ismbblead)(unsigned int Ch); 76 | // PFN_ismbblead pfn_ismbblead = (PFN_ismbblead)g_pfnOlds[1]; 77 | // return pfn_ismbblead(Ch); 78 | if(Ch > 0x80) return 1; 79 | else return 0; 80 | } 81 | 82 | int __cdecl _setmbcp_hook(int CodePage) 83 | { 84 | typedef int (*PFN_setmbcp)(int CodePage); 85 | PFN_setmbcp pfn_setmbcp = (PFN_setmbcp)g_pfnOlds[2]; 86 | CodePage = 936; 87 | return pfn_setmbcp(CodePage); 88 | } 89 | 90 | int __cdecl decodelzss_44850C_hook( 91 | char *compressed_buf, char *raw_buf, int default_return) 92 | { 93 | struct ffalzss_t* ffalzss = (struct ffalzss_t*)compressed_buf; 94 | // dirty fix for hcg loading 95 | if(0) 96 | { 97 | typedef int (*PFN_decodelzss)(char*, char*, int); 98 | PFN_decodelzss pfn_deocdelzss = g_pfnOlds[0]; 99 | return pfn_deocdelzss(compressed_buf, raw_buf, default_return); 100 | } 101 | 102 | uint32_t* pdword_45B910 = (uint32_t*)0x45B910; 103 | uint32_t* pdword_45B914 = (uint32_t*)0x45B914; 104 | uint32_t* pdword_45B920 = (uint32_t*)0x45B920; 105 | *pdword_45B910 = (uint32_t)compressed_buf; 106 | *pdword_45B914 = (uint32_t)raw_buf; 107 | *pdword_45B920 = (uint32_t)default_return; 108 | lzss_decode(ffalzss->data, raw_buf, ffalzss->zsize); 109 | return default_return; 110 | } 111 | 112 | void install_fonthook() 113 | { 114 | // hook CreateFontIndirectA 115 | if(!winhook_iathook("gdi32.dll", GetProcAddress( 116 | GetModuleHandleA("gdi32.dll"), "CreateFontIndirectA"), 117 | (PROC)CreateFontIndirectA_hook)) 118 | { 119 | MessageBoxA(0, "CreateFontIndirectA hook error", "IAThook error", 0); 120 | } 121 | } 122 | 123 | PVOID g_pfnTargets[] = { 124 | (PVOID)0x44850C, 125 | (PVOID)0x44BD90, 126 | (PVOID)0x44B9B0}; 127 | PVOID g_pfnNews[] = { 128 | (PVOID)decodelzss_44850C_hook, 129 | (PVOID)_ismbblead_hook, 130 | (PVOID)_setmbcp_hook}; 131 | PVOID g_pfnOlds[sizeof(g_pfnTargets)/sizeof(PVOID)]; 132 | 133 | void install_hooks() 134 | { 135 | #ifdef _DEBUG 136 | AllocConsole(); 137 | freopen("CONOUT$", "w", stdout); 138 | printf("install hook, v0.1, build in 220702\n"); 139 | #endif 140 | install_fonthook(); 141 | winhook_inlinehooks( 142 | g_pfnTargets, g_pfnNews, g_pfnOlds, 143 | sizeof(g_pfnTargets)/sizeof(PVOID)); 144 | } 145 | 146 | BOOL WINAPI DllMain( 147 | HINSTANCE hinstDLL, // handle to DLL module 148 | DWORD fdwReason, // reason for calling function 149 | LPVOID lpReserved ) // reserved 150 | { 151 | switch( fdwReason ) 152 | { 153 | case DLL_PROCESS_ATTACH: 154 | install_hooks(); 155 | #ifdef USE_DVFS 156 | windvfs_install(); 157 | #endif 158 | break; 159 | case DLL_THREAD_ATTACH: 160 | break; 161 | case DLL_THREAD_DETACH: 162 | break; 163 | case DLL_PROCESS_DETACH: 164 | break; 165 | } 166 | return TRUE; 167 | } 168 | 169 | /* 170 | * history 171 | * v0.1, support amanomiko new version lzss and gbk 172 | * v0.1.1, fix hcg with lzss format 173 | */ -------------------------------------------------------------------------------- /project/ffa/src/amanomiko_pt1.py: -------------------------------------------------------------------------------- 1 | """ 2 | parsing PT1 image file rgb24 format for 天巫女姫, 3 | v0.1, developed by devseed 4 | 5 | """ 6 | 7 | import os 8 | import sys 9 | import struct 10 | import numpy as np 11 | from io import BytesIO 12 | from PIL import Image 13 | 14 | import amanomiko_lzss as amalzss 15 | 16 | class pt1_t(struct.Struct): 17 | def __init__(self, data): 18 | super().__init__('6I') 19 | self.frombytes(data) 20 | 21 | def frombytes(self, data): 22 | self.data = data 23 | (self.type, self.reserve1, 24 | self.x, self.y, self.height, self.width) = \ 25 | self.unpack_from(self.data, 0) 26 | 27 | def tobytes(self): 28 | self.x, self.y, 29 | self.pack_into(self.data, 0, 30 | self.type, self.reserve1, self.x, self.y, 31 | self.height, self.width) 32 | return self.data 33 | 34 | def export_pt1(pt1path, outpath="out.png"): 35 | """ 36 | this function has problem except type v0, 37 | see https://github.com/morkt/PopulateLzssFrame/blob/master/ArcFormats/Ffa/ImagePT1.cs 38 | """ 39 | 40 | with open(pt1path, 'rb') as fp: 41 | data = memoryview(bytearray(fp.read())) 42 | pt1 = pt1_t(data) 43 | 44 | rawdata, rawsize = amalzss.decode_lzss(data[pt1.size: ], outpath=outpath) 45 | if rawsize != pt1.height * pt1.width * 3: 46 | raise ValueError(f"pt1 decode error: {rawsize}!={pt1.height}X{pt1.width}X3") 47 | return rawdata 48 | 49 | def import_pt1(imgpath, orgpt1path, outpath="out.PT1"): 50 | """ 51 | only support for type0 rebuild 52 | """ 53 | 54 | with open(orgpt1path, 'rb') as fp: 55 | data = bytearray(fp.read(0x18)) 56 | pt1 = pt1_t(data) 57 | pt1.type = 0 58 | 59 | bufio = BytesIO() 60 | bufio.write(pt1.tobytes()) 61 | bgr = np.array(Image.open(imgpath)) 62 | bgr = bgr[:,:, [2,1,0]] 63 | buf, zsize = amalzss.encode_lzss(memoryview(bgr.flatten()), "") 64 | bufio.write(buf[:zsize + 8]) 65 | 66 | if outpath != "": 67 | with open(outpath, 'wb') as fp: 68 | fp.write(bufio.getbuffer()) 69 | return bufio.getbuffer() 70 | 71 | def debug(): 72 | export_pt1("./build/intermediate/G1WIA/EHTB0101.PT1") 73 | # import_pt1("./build/intermediate/G1WIA_png/G1_TIT0.png", "./build/intermediate/G1WIA/G1_TIT0.PT1") 74 | pass 75 | 76 | def main(): 77 | if len(sys.argv) < 3: 78 | print("PT1 e pt1path [outpath]") 79 | print("PT1 i imgpath orgpt1path [outpath]") 80 | return 81 | if sys.argv[1].lower() == 'e': 82 | outpath = sys.argv[3] if len(sys.argv) > 3 else "out.txt" 83 | export_pt1(sys.argv[2], outpath) 84 | elif sys.argv[1].lower() == 'i': 85 | outpath = sys.argv[4] if len(sys.argv) > 4 else "out.bin" 86 | import_pt1(sys.argv[2], sys.argv[3], outpath) 87 | else: raise ValueError(f"unknow format {sys.argv[1]}") 88 | 89 | if __name__ == '__main__': 90 | # debug() 91 | main() 92 | pass -------------------------------------------------------------------------------- /project/ffa/src/liblzss20.c: -------------------------------------------------------------------------------- 1 | #define LZSS_IMPLEMENTATION 2 | #define LZSS_SHARED 3 | #define LZSS_DECINITBYTE 0X20 4 | #define LZSS_ENCINITBYTE 0X20 5 | #ifdef USE_COMPAT 6 | #include "lzss_v1000.h" 7 | #else 8 | #include "lzss.h" 9 | #endif -------------------------------------------------------------------------------- /project/hibiki/src/hibiki_kstext.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | for nature valaciton chs localization, 4 | export and import text in hibiki kag format 5 | v0.1, developed by devseed 6 | """ 7 | 8 | import re 9 | import codecs 10 | import argparse 11 | 12 | # ●p000|9999|[name]● text, 13 | # the text can not be multi line, should be using r'\n' in the inner text, no need to put r'\n' in the end 14 | 15 | def extract_hibiki_ks(inpath, outpath): 16 | def _next_validline(i): 17 | while i < len(lines): 18 | line = lines[i].lstrip().strip('\n').strip('\r') 19 | if line == "": i += 1 20 | else: break 21 | return i 22 | 23 | fin = codecs.open(inpath, 'r', 'utf-8') 24 | fout = codecs.open(outpath, 'w', 'utf-8') 25 | lines = fin.readlines() 26 | i = 0 27 | while i < len(lines): 28 | text = "" 29 | name = "" 30 | p_idx = "" 31 | line = lines[i].lstrip().strip('\n').strip('\r') 32 | # print(line) 33 | 34 | if line=="" or line[0]==';': 35 | i += 1 36 | continue 37 | 38 | if line[0] == '*' and line[1] == 'p': # text 39 | p_idx = line[1:-1] 40 | i = _next_validline(i+1) 41 | 42 | while i < len(lines): 43 | line = lines[i].lstrip().strip('\n').strip('\r') 44 | if line == "" or line[0] == "*": 45 | break 46 | if line[0]==";": 47 | i += 1 48 | continue 49 | if line.find("@nm") != -1: 50 | m = re.search(r"@nm\s*t=\"(.+?)\"", line) 51 | name = m.group(1) if m is not None else name 52 | if name!="": 53 | fout.write("○{p_idx}|{i:04d}|{name}○\n" 54 | .format(p_idx=p_idx, i=i, name=name)) 55 | fout.write("●{p_idx}|{i:04d}|{name}●\n\n" 56 | .format(p_idx=p_idx, i=i, name=name)) 57 | i = _next_validline(i+1) 58 | else: i+= 1 59 | elif line[0] != "@" : 60 | text = lines[i] 61 | if text!="": 62 | fout.write("○{p_idx}|{i:04d}|○ {text}" 63 | .format(p_idx=p_idx, i=i, text=text)) 64 | fout.write("●{p_idx}|{i:04d}|● {text}\n" 65 | .format(p_idx=p_idx, i=i, text=text )) 66 | i += 1 67 | i += 1 68 | fin.close() 69 | fout.close() 70 | 71 | def import_hibiki_ks(textpath, insertpath, outpath): 72 | ftext = codecs.open(textpath, 'r', 'utf-8') 73 | fins = codecs.open(insertpath, 'r', 'utf-8') 74 | fout = codecs.open(outpath, 'wb', 'utf-8') 75 | lines_ins = fins.readlines() 76 | lines_text = ftext.readlines() 77 | re_line = re.compile(r"●(.*)\|(\d*)\|(.*)●[ ](.*)") 78 | for line in lines_text: 79 | line = line.strip("\n") 80 | m = re_line.match(line) 81 | if m is not None: 82 | idx = int(m.group(2)) 83 | name = m.group(3) 84 | text = m.group(4) 85 | # print(idx, name, text) 86 | if name!="": 87 | lines_ins[idx] = re.sub(r"@nm\s*t=\"(.+?)\"(.*)$", '@nm t="' + name+'"'+ r"\2", lines_ins[idx]) 88 | else: 89 | lines_ins[idx] = text + '\n' 90 | for line in lines_ins: 91 | # print(line) 92 | fout.write(line) 93 | ftext.close() 94 | fins.close() 95 | fout.close() 96 | 97 | def main(): 98 | parser = argparse.ArgumentParser(description = 'extract or insert text in hibiki ks text') 99 | parser.add_argument('input', type=str) 100 | parser.add_argument('--insert', '-i', type=str, default="", help='insert the text to script') 101 | parser.add_argument('--output', '-o', type=str, default="", help='output utf-8 sjis text path') 102 | args = parser.parse_args() 103 | inpath = args.input 104 | outpath = args.output 105 | 106 | if args.insert != "": 107 | if outpath=="": outpath = inpath+'.ks' 108 | import_hibiki_ks(inpath, args.insert, outpath) 109 | else: 110 | if outpath=="": outpath = inpath+'.txt' 111 | extract_hibiki_ks(inpath, outpath) 112 | 113 | def debug(): 114 | extract_hibiki_ks(r"01姉_00_01.ks", r"01姉_00_01.ks.txt") 115 | 116 | if __name__=='__main__': 117 | # debug() 118 | main() 119 | pass -------------------------------------------------------------------------------- /project/hibiki/src/hibiki_rename_picture.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | for nature valaciton chs localization, 4 | renaming sjis to crc32 5 | v0.1, developed by devseed 6 | """ 7 | 8 | import os 9 | import shutil 10 | import zlib 11 | import codecs 12 | import re 13 | 14 | def renmae_iamge(image_dir, ext=[".png"], rename_dir=""): 15 | file_map = dict() 16 | if rename_dir=="": rename_dir = os.path.join(image_dir, "rename") 17 | if not os.path.exists(rename_dir): os.makedirs(rename_dir) 18 | for file in os.listdir(image_dir): 19 | if os.path.splitext(file)[1].lower() not in ext: continue 20 | rename_crc32 = "%08X" %zlib.crc32(file.encode("utf-8")) + ".png" 21 | file_map[os.path.splitext(file)[0]] = rename_crc32 22 | print(os.path.join(rename_dir, rename_crc32)) 23 | shutil.copyfile(os.path.join(image_dir, file), os.path.join(rename_dir, rename_crc32)) 24 | # print("%s -> %s" %(file, rename_crc32)) 25 | return file_map 26 | 27 | def rename_script(script_path, file_map, rename_path=""): 28 | print("processing file " + script_path + "...") 29 | if rename_path=="": rename_path = script_path 30 | lines = [] 31 | with codecs.open(script_path, 'r', 'utf-8') as fp: 32 | lines = fp.readlines() 33 | flag = False 34 | for i, line in enumerate(lines): 35 | m = re.search(r"\[storage:(.+?),", line) 36 | if m!=None and m.group(1) in file_map: 37 | flag = True 38 | orgpath = m.group(1) 39 | dstpath = "imagechs/" + file_map[orgpath] 40 | lines[i] = lines[i].replace(orgpath, dstpath) 41 | print("%s -> %s" %(orgpath, dstpath)) 42 | continue 43 | m = re.search(r"\[storage:\"(.+?)\",", line) 44 | if m!=None and m.group(1) in file_map: 45 | flag = True 46 | orgpath = m.group(1) 47 | dstpath = "imagechs/" + file_map[orgpath] 48 | lines[i] = lines[i].replace(orgpath, dstpath) 49 | print("%s -> %s" %(orgpath, dstpath)) 50 | continue 51 | 52 | if flag: 53 | with codecs.open(rename_path, 'w', 'utf-8') as fp: 54 | fp.writelines(lines) 55 | 56 | def main(): 57 | intermediate_dir= r".\build\intermediate" 58 | image_dir = os.path.join(intermediate_dir, "imagechs") 59 | image_rename_dir = os.path.join(intermediate_dir, "imagechs_hased") 60 | script_dir = os.path.join(intermediate_dir, "data_rebuild") 61 | script_rename_dir = os.path.join(intermediate_dir, "data_rebuild_hased") 62 | file_map = renmae_iamge(image_dir, rename_dir=image_rename_dir) 63 | for file in os.listdir(script_dir): 64 | if os.path.splitext(file)[1] not in ['.csv']: 65 | continue 66 | rename_script(os.path.join(script_dir, file), file_map, 67 | os.path.join(script_rename_dir, file)) 68 | 69 | if __name__ == '__main__': 70 | main() -------------------------------------------------------------------------------- /project/hobibox/src/liblzss64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuriSizuku/GalgameReverse/e9e309986dd51ed65fc7c26c87de1d5f516cbc89/project/hobibox/src/liblzss64.dll -------------------------------------------------------------------------------- /project/hobibox/src/narcissus_psp_lzss.py: -------------------------------------------------------------------------------- 1 | """ 2 | parsing lzss structure with header for Narcissus psp, 3 | v0.1, developed by devseed 4 | 5 | """ 6 | 7 | import os 8 | import sys 9 | import mmap 10 | from ctypes import CDLL, addressof, c_char, c_char_p, c_size_t 11 | 12 | try: 13 | g_lzmadll = CDLL(os.path.join(os.path.dirname(sys.argv[0]), "liblzss64.dll")) 14 | except FileNotFoundError as e: 15 | g_lzmadll = CDLL("./liblzss64.dll") 16 | g_lzmadll.lzss_encode.argtypes = [c_char_p, c_char_p, c_size_t] 17 | g_lzmadll.lzss_encode.restype = c_size_t 18 | g_lzmadll.lzss_decode.argtypes = [c_char_p, c_char_p, c_size_t] 19 | g_lzmadll.lzss_decode.restype = c_size_t 20 | 21 | def decode_lzss(inpath, outpath="out"): 22 | fd = os.open(inpath, os.O_RDWR) 23 | data = mmap.mmap(fd, 0) 24 | rawsize = int.from_bytes(data[0:4], 'little', signed=False) 25 | bufsrc = c_char * (len(data) -4) 26 | bufdst = (c_char * rawsize)() 27 | dstsize = g_lzmadll.lzss_decode( 28 | bufsrc.from_buffer(data, 4), bufdst, len(data)-4) 29 | os.close(fd) 30 | 31 | if dstsize != rawsize: 32 | raise ValueError(f"decode data size wrong {dstsize:x}!={rawsize:x}") 33 | 34 | if outpath: 35 | with open(outpath, 'wb') as fp: 36 | fp.write(bufdst.raw[:dstsize]) 37 | return bufdst.raw, dstsize 38 | 39 | def encode_lzss(inpath, outpath="out"): 40 | fd = os.open(inpath, os.O_RDWR) 41 | data = mmap.mmap(fd, 0) 42 | bufsrc = c_char * (len(data)) 43 | bufdst = (c_char * (len(data)))() 44 | dstsize = g_lzmadll.lzss_encode( 45 | bufsrc.from_buffer(data), 46 | c_char_p(addressof(bufdst)+4), len(data)) 47 | bufdst[0:4] = int.to_bytes( 48 | len(data), 4, 'little', signed=False) 49 | os.close(fd) 50 | if outpath: 51 | with open(outpath, 'wb') as fp: 52 | fp.write(bufdst[:dstsize+4]) 53 | return bufdst, dstsize 54 | 55 | def debug(): 56 | decode_lzss("./build/intermediate/sn.bin") 57 | encode_lzss("./build/intermediate/sn.bin.dec") 58 | 59 | def main(): 60 | if len(sys.argv) < 3: 61 | print("Narcissus_lzss e inpath [outpath]") 62 | print("Narcissus_lzss d inpath [outpath]") 63 | return 64 | 65 | outpath = sys.argv[3] if len(sys.argv) > 3 else "out" 66 | if sys.argv[1].lower() == 'e': 67 | encode_lzss(sys.argv[2], outpath) 68 | elif sys.argv[1].lower() == 'd': 69 | decode_lzss(sys.argv[2], outpath) 70 | else: raise ValueError(f"unknow format {sys.argv[1]}") 71 | 72 | if __name__ == '__main__': 73 | # debug() 74 | main() 75 | pass -------------------------------------------------------------------------------- /project/hobibox/src/narcissus_psp_sn.py: -------------------------------------------------------------------------------- 1 | """ 2 | to export or import sn.bin (after decompress) for Narcissus psp, 3 | v0.1, developed by devseed 4 | """ 5 | 6 | import os 7 | import sys 8 | import struct 9 | from glob import glob 10 | from io import SEEK_END, SEEK_SET, BytesIO 11 | from typing import List 12 | from collections import namedtuple 13 | 14 | snidx_t = namedtuple("narsn_indexnode", ['offset', 'size']) 15 | 16 | def load_snidxs(data) -> List[snidx_t]: 17 | end = int.from_bytes(data[0:4], 'little', signed=False) 18 | cur = 0 19 | narsn_indexs: List[snidx_t] = [] 20 | while cur < end: 21 | offset, size = struct.unpack("<2I", data[cur: cur+8]) 22 | narsn_indexs.append(snidx_t(offset, size)) 23 | cur += 0x10 24 | return narsn_indexs 25 | 26 | def dump_snidxs(narsn_indexs: List[snidx_t]): 27 | dataio = BytesIO() 28 | for t in narsn_indexs: 29 | dataio.write(struct.pack("<4I", t.offset, t.size, 0, 0)) 30 | return dataio.getbuffer() 31 | 32 | def export_sn(inpath, outdir="./out"): 33 | with open(inpath, 'rb') as fp: 34 | data = fp.read() 35 | narsn_indexs = load_snidxs(data) 36 | 37 | if outdir != "./out": 38 | name = os.path.splitext(os.path.basename(inpath))[0] 39 | for i, t in enumerate(narsn_indexs): 40 | outpath = os.path.join(outdir, f"{name}_{i:02d}.bin") 41 | with open(outpath, 'wb') as fp: 42 | fp.write(data[t.offset: t.offset + t.size]) 43 | 44 | return narsn_indexs 45 | 46 | def import_sn(indir, orgpath, outpath="out.bin"): 47 | # load origin sn.bin 48 | with open(orgpath, 'rb') as fp: 49 | orgdata = fp.read() 50 | narsn_indexs = load_snidxs(orgdata) 51 | 52 | # import file data 53 | shift = 0 54 | align = 0x10 55 | bufio = BytesIO(len(narsn_indexs)*0x10*b'\x00') 56 | bufio.seek(0, SEEK_END) 57 | filelist: List[str] = glob(os.path.join(indir, "*.bin")) 58 | for i, t in enumerate(narsn_indexs): 59 | findidx = -1 60 | for j, file in enumerate(filelist): 61 | if file.find(f"{i:02d}.bin") != -1: 62 | findidx = j 63 | break 64 | if findidx == -1: 65 | bufio.write(orgdata[t.offset: t.offset + t.size]) 66 | addsize = 0 67 | else: 68 | with open (filelist[findidx], 'rb') as fp: 69 | data = fp.read() 70 | padsize = 0 71 | if len(data)%align: 72 | padsize = align - len(data)%align 73 | bufio.write(data) 74 | bufio.write(b'\x00' * padsize) 75 | addsize = len(data) + padsize - t.size 76 | 77 | if shift != 0 or addsize != 0: 78 | print(f"{i}, {filelist[findidx]}, " 79 | f"offset {t.offset:x}->{t.offset+shift:x}, " 80 | f"size {t.size:x}->{t.size+addsize:x}") 81 | narsn_indexs[i] = snidx_t(t.offset+shift, t.size + addsize) 82 | shift += addsize 83 | assert(narsn_indexs[i].offset + narsn_indexs[i].size == bufio.tell()) 84 | 85 | # rebuild the index 86 | bufio.seek(0, SEEK_SET) 87 | bufio.write(dump_snidxs(narsn_indexs)) 88 | 89 | if outpath!="": 90 | with open(outpath, 'wb') as fp: 91 | fp.write(bufio.getbuffer()) 92 | 93 | return bufio.getbuffer() 94 | 95 | def debug(): 96 | export_sn("./build/intermediate/sn.bin.dec", "./build/intermediate/sn") 97 | import_sn("./build/intermediate/sn_rebuild/", "./build/intermediate/sn.bin.dec", "./build/intermediate/sn_rebuild.bin.dec") 98 | pass 99 | 100 | def main(): 101 | if len(sys.argv) < 3: 102 | print("Narcissus_sn e inpath [outdir]") 103 | print("Narcissus_sn i indir orgpath [outpath]") 104 | return 105 | if sys.argv[1].lower() == 'e': 106 | outdir = sys.argv[3] if len(sys.argv) > 3 else "./out" 107 | export_sn(sys.argv[2], outdir) 108 | elif sys.argv[1].lower() == 'i': 109 | outpath = sys.argv[4] if len(sys.argv) > 4 else "out.bin" 110 | import_sn(sys.argv[2], sys.argv[3], outpath) 111 | else: raise ValueError(f"unknow format {sys.argv[1]}") 112 | 113 | if __name__ == '__main__': 114 | # debug() 115 | main() 116 | pass -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/_env.bat: -------------------------------------------------------------------------------- 1 | set BASE_DIR=D:\Make\reverse\Narcissus_psp 2 | set GAME_DIR=D:\Make\reverse\Narcissus_psp\ULJM05674 3 | set GAME_LAUNCHER=D:\Game\emulator\PSP\PPSSPPWindows64.exe 4 | set WORKFLOW_DIR=D:\Make\reverse\Narcissus_psp\workflow 5 | set WORKFLOW2_DIR=D:\Make\reverse\Narcissus_psp\workflow2 6 | set RESULT_DIR=D:\Make\reverse\Narcissus_psp\workflow\5.result 7 | set SRC_DIR=%~dp0..\..\src 8 | set TOOL_DIR=%~dp0..\..\tool -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/build_1font.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | python -B %SRC_DIR%\narcissus_psp_2bppfont.py c932 workflow\2.pre\font\font_sjis.tbl workflow\3.edit\default.ttf workflow\1.origin\font.bin workflow\4.post\font 5 | move /y workflow\4.post\font\font_rebuild.bin %RESULT_DIR%\USRDIR\font.bin 6 | copy /y workflow\4.post\font\font_chs.tbl workflow\4.post\narcissus_psp_chs.tbl -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/build_2sn.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | chcp 65001 3 | call _env.bat 4 | 5 | for /f "delims=" %%i in ('dir /b workflow\3.edit\sn_ftext\*.txt') do ( 6 | echo %%i 7 | python -B %SRC_DIR%\narcissus_psp_sntext.py i workflow\3.edit\sn_ftext\%%i workflow\2.pre\sn\%%~ni workflow\4.post\narcissus_psp_chs.tbl workflow\4.post\sn\%%~ni 8 | ) 9 | 10 | :: rebuild sn_00.bin, this can not be longer 11 | python -B %SRC_DIR%\compat\bintext_v580.py workflow\3.edit\sn_ftext\sn_00.bin.txt -p workflow\2.pre\sn\sn_00.bin --tbl workflow\4.post\narcissus_psp_chs.tbl -o workflow\4.post\sn\sn_00.bin --replace_map 〜:~ --padding_bytes 32 12 | 13 | python -B %SRC_DIR%\narcissus_psp_sn.py i workflow\4.post\sn workflow\2.pre\sn.bin.dec workflow\4.post\sn.bin.dec 14 | python -B %SRC_DIR%\narcissus_psp_lzss.py e workflow\4.post\sn.bin.dec %RESULT_DIR%\USRDIR\sn.bin -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/build_3lbg.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | for /f "delims=" %%i in ('dir /b workflow2\3.edit\bg_png\*.png') do ( 5 | echo %%i 6 | python %SRC_DIR%\narcissus_psp_lbg.py invf workflow2\3.edit\bg_png\%%i workflow2\4.post\bg_png2\%%i 7 | python %SRC_DIR%\narcissus_psp_lbg.py i workflow2\4.post\bg_png2\%%i workflow2\2.pre\bg_dec\%%~ni.dec workflow2\4.post\bg_dec\%%~ni.dec 8 | python %SRC_DIR%\narcissus_psp_lzss.py e workflow2\4.post\bg_dec\%%~ni.dec workflow2\4.post\bg\%%~ni 9 | echo ## 10 | ) 11 | 12 | copy /y workflow2\2.pre\bg.afs.txt workflow2\4.post\bg.afs.txt 13 | pushd workflow2\4.post 14 | "%TOOL_DIR%\AFSPacker_sjis.exe" -c .\bg "%RESULT_DIR%\USRDIR\bg.afs" .\bg.afs.txt 15 | popd -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/build_3sys.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | echo ## convert png to gim 5 | for /f "delims=" %%i in ('dir /b /s workflow2\3.edit\sys_png\*.png') do ( 6 | echo %%i 7 | "%TOOL_DIR%\GimConv\GimConv.exe" "%%i" -o "%%~dpni" --format_style psp --format_endian little 8 | ) 9 | 10 | echo ## fix some gim to index8 mode 11 | "%TOOL_DIR%\GimConv\GimConv.exe" workflow2\3.edit\sys_png\sv.spc\sv.spc_20.gim.png -o sv.spc_20.gim --format_style psp --format_endian little --image_format index8 12 | "%TOOL_DIR%\GimConv\GimConv.exe" workflow2\3.edit\sys_png\sv.spc\sv.spc_25.gim.png -o sv.spc_25.gim --format_style psp --format_endian little --image_format index8 13 | "%TOOL_DIR%\GimConv\GimConv.exe" workflow2\3.edit\sys_png\sv.spc\sv.spc_44.gim.png -o sv.spc_44.gim --format_style psp --format_endian little --image_format index8 14 | 15 | echo ## move gim and prepare to pack 16 | xcopy /f /s /y workflow2\3.edit\sys_png\*.gim workflow2\4.post\sys_gim 17 | del /s /q workflow2\3.edit\sys_png\*.gim 18 | for /f "delims=" %%i in ('dir /b /s workflow2\4.post\sys_gim\*.gim') do ( 19 | echo %%i 20 | move "%%i" "%%~dpni.bin" 21 | ) 22 | 23 | echo ## pack gim and compress to spc 24 | for /f "delims=" %%i in ('dir /b /a:d workflow2\4.post\sys_gim') do ( 25 | echo %%i 26 | python %SRC_DIR%\narcissus_psp_sn.py i workflow2\4.post\sys_gim\%%i workflow2\2.pre\sys_dec\%%i.dec workflow2\4.post\sys_dec\%%i.dec 27 | python %SRC_DIR%\narcissus_psp_lzss.py e workflow2\4.post\sys_dec\%%i.dec workflow2\4.post\sys\%%i 28 | ) 29 | 30 | echo ## pack afs 31 | copy /y workflow2\2.pre\sys.afs.txt workflow2\4.post\sys.afs.txt 32 | pushd workflow2\4.post 33 | "%TOOL_DIR%\AFSPacker_sjis.exe" -c .\sys "%RESULT_DIR%\USRDIR\sys.afs" .\sys.afs.txt 34 | popd -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/build_4eboot.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | chcp 65001 3 | call _env.bat 4 | 5 | python -B %SRC_DIR%\compat\bintext_v580.py workflow\3.edit\EBOOT.BIN.txt -p workflow\1.origin\EBOOT.BIN --tbl workflow\4.post\narcissus_psp_chs.tbl -o %RESULT_DIR%\SYSDIR\EBOOT.BIN --replace_map ·:・ 6 | copy /y %RESULT_DIR%\SYSDIR\EBOOT.BIN %RESULT_DIR%\SYSDIR\BOOT.BIN -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/convert_fixlbg.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | for /f "delims=" %%i in ('dir /b %1\*.png') do ( 5 | echo %%i 6 | python %SRC_DIR%\narcissus_psp_lbg.py f %1\%%i %2\%%i 7 | ) -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/convert_invfixlbg.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | for /f "delims=" %%i in ('dir /b %1\*.png') do ( 5 | echo %%i 6 | python %SRC_DIR%\narcissus_psp_lbg.py invf %1\%%i %2\%%i 7 | ) -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/extract_lbg.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | for /f "delims=" %%i in ('dir /b %1\*.lbg') do ( 5 | echo %%i 6 | python %SRC_DIR%\narcissus_psp_lbg.py e %1\%%i %1\%%~ni.png 7 | ) -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/extract_lzss.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | for /f "delims=" %%i in ('dir /b %1\*') do ( 5 | echo %%i 6 | python %SRC_DIR%\narcissus_psp_lzss.py d %1\%%i %1\%%i.dec 7 | ) -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/extract_sn.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | for /f "delims=" %%i in ('dir /b %1\*') do ( 5 | echo %%i 6 | mkdir %1\%%~ni 7 | python %SRC_DIR%\narcissus_psp_sn.py e %1\%%i %1\%%~ni 8 | ) -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/init.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | if not exist "%~dp0/workflow" ( 5 | mklink /j workflow %WORKFLOW_DIR% 6 | ) 7 | 8 | if not exist "%~dp0/workflow2" ( 9 | mklink /j workflow2 %WORKFLOW2_DIR% 10 | ) -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/run.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | echo %GAME_LAUNCHER% 5 | start %GAME_LAUNCHER% "%GAME_DIR%" -------------------------------------------------------------------------------- /project/hobibox/task/task_narcissuspsp/send.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call _env.bat 3 | 4 | xcopy /y /s %RESULT_DIR%\* %GAME_DIR%\PSP_GAME -------------------------------------------------------------------------------- /project/hunex/src/hunex_hlzs.py: -------------------------------------------------------------------------------- 1 | """ 2 | for decoding hlzs format (script_dialog_xx.hdlg) in hunex engine 3 | v0.1, developed by devseed 4 | 5 | tested game: 6 | 明治東亰恋伽 7 | 8 | """ 9 | 10 | import sys 11 | import io 12 | import ctypes 13 | 14 | import numba 15 | import numpy as np 16 | from numba import njit, uint8, int32 17 | readonly = lambda dtype, dim: numba.types.Array(dtype, dim, "C", True) 18 | 19 | class hlzs_header_t(ctypes.Structure): 20 | _fields_ = [ 21 | ("id", ctypes.c_uint32), 22 | ("version", ctypes.c_uint32), 23 | ("encodeSize", ctypes.c_uint32), 24 | ("decodeSize", ctypes.c_uint32), 25 | ] 26 | 27 | def decode_lzs(inbuf: memoryview, DICT_SIZE=0x1000, MAX_LEN=0x12) -> memoryview: 28 | dictbuf = memoryview(bytearray(b'\x00' * DICT_SIZE)) 29 | outio = io.BytesIO() # outbuf sync with dict 30 | flag8 = 1 # flags for next 8 itmes 31 | inpos, dictpos = 0, 0 32 | 33 | while inpos < len(inbuf): 34 | if flag8 == 1: 35 | flag8 = inbuf[inpos] | 0x100 36 | inpos += 1 37 | flag = flag8 & 0x1 38 | flag8 >>= 1 39 | if flag: # direct copy 40 | c = inbuf[inpos: inpos+1] 41 | inpos += 1 42 | outio.write(c) 43 | dictbuf[dictpos: dictpos+1] = c 44 | dictpos = (dictpos + 1) & (DICT_SIZE -1) # circle dict buf write 45 | else: # dict copy 46 | low, high = inbuf[inpos: inpos+2] 47 | inpos += 2 48 | wordpos, wordsize = ((high & 0xf0) << 4 | low) + MAX_LEN, (high & 0x0f) + 3 49 | for i in range(wordsize): 50 | pos = (wordpos + i) & (DICT_SIZE -1) 51 | c = dictbuf[pos: pos+1] 52 | outio.write(c) 53 | dictbuf[dictpos: dictpos+1] = c # write back to dict 54 | dictpos = (dictpos + 1) & (DICT_SIZE -1) 55 | 56 | return outio.getbuffer() 57 | 58 | @njit([int32(readonly(uint8, 1), int32,uint8[:], int32, uint8[:], int32)]) 59 | def decode_lzs_fast(inbuf, insize, dictbuf, dictsize, outbuf, outsize): 60 | MAX_LEN = 0x12 61 | flag8 = 1 # flags for next 8 itmes 62 | inpos, outpos, dictpos = 0, 0, 0 63 | 64 | while inpos < insize: 65 | if outpos >= outsize: return 0 66 | if flag8 == 1: 67 | flag8 = inbuf[inpos] | 0x100 68 | inpos += 1 69 | flag = flag8 & 0x1 70 | flag8 >>= 1 71 | if flag: # direct copy 72 | c = inbuf[inpos] 73 | inpos += 1 74 | outbuf[outpos] = c 75 | outpos += 1 76 | dictbuf[dictpos] = c 77 | dictpos = (dictpos + 1) & (dictsize -1) # circle dict buf write 78 | else: # dict copy 79 | low, high = inbuf[inpos], inbuf[inpos+1] 80 | inpos += 2 81 | wordpos, wordsize = ((high & 0xf0) << 4 | low) + MAX_LEN, (high & 0x0f) + 3 82 | for i in range(wordsize): 83 | pos = (wordpos + i) & (dictsize -1) 84 | c = dictbuf[pos] 85 | outbuf[outpos] = c 86 | outpos += 1 87 | dictbuf[dictpos] = c # write back to dict 88 | dictpos = (dictpos + 1) & (dictsize -1) 89 | 90 | return outpos 91 | 92 | def decode_hlzs(hlzsbuf: memoryview, use_fast_lzs=True) -> memoryview: 93 | hlzs_header = hlzs_header_t.from_buffer_copy(hlzsbuf) 94 | assert(hlzs_header.id == int.from_bytes(b"HLZS", "little", signed=False)) 95 | if use_fast_lzs: 96 | inbuf = np.frombuffer(hlzsbuf, dtype=np.uint8, offset=0x20, count=hlzs_header.encodeSize) 97 | outbuf = np.zeros(hlzs_header.decodeSize, dtype=np.uint8) 98 | dictbuf = np.zeros(0x1000, dtype=np.uint8) 99 | outsize = decode_lzs_fast(inbuf, inbuf.nbytes, dictbuf, dictbuf.nbytes, outbuf, outbuf.nbytes) 100 | assert(outsize == hlzs_header.decodeSize) 101 | outbuf = memoryview(outbuf) 102 | else: 103 | inbuf = memoryview(hlzsbuf[0x20: 0x20 + hlzs_header.encodeSize]) 104 | outbuf = decode_lzs(inbuf) 105 | assert(len(outbuf) == hlzs_header.decodeSize) 106 | 107 | return outbuf 108 | 109 | def main(argv): 110 | if len(argv) < 2: 111 | print("hunex_hlzs inpath [outpath]") 112 | return 113 | inpath = argv[1] 114 | outpath = inpath + ".dec" if len(argv) < 3 else argv[2] 115 | with open(inpath, 'rb') as fp: 116 | inbuf = memoryview(fp.read()) 117 | outbuf = decode_hlzs(inbuf) 118 | with open(outpath, "wb") as fp: 119 | fp.write(outbuf) 120 | 121 | if __name__ == "__main__": 122 | main(sys.argv) -------------------------------------------------------------------------------- /project/hunex/src/hunex_hpb.py: -------------------------------------------------------------------------------- 1 | """ 2 | for decoding hpb(hph) format in hunex engine 3 | v0.1, developed by devseed 4 | 5 | tested game: 6 | 明治東亰恋伽 7 | 8 | """ 9 | 10 | import os 11 | import sys 12 | import ctypes 13 | from zlib import crc32 14 | 15 | from hunex_hlzs import decode_hlzs 16 | 17 | class hpac_header_t(ctypes.Structure): 18 | _fields_ = [ 19 | ("id", ctypes.c_uint32), 20 | ("version", ctypes.c_uint32), 21 | ("count", ctypes.c_int32), 22 | ("size", ctypes.c_uint32), 23 | ("nameOffset", ctypes.c_uint32), 24 | ("padding", ctypes.c_void_p), 25 | ] 26 | 27 | class hpac_entry_t(ctypes.Structure): 28 | _fields_ = [ 29 | ("offset", ctypes.c_int64), 30 | ("key", ctypes.c_uint32), 31 | ("fileSize", ctypes.c_uint32), 32 | ("meltSize", ctypes.c_uint32), 33 | ("fileCRC", ctypes.c_uint32), 34 | ("meltCRC", ctypes.c_uint32), 35 | ] 36 | 37 | def extract_hpb(hpbpath, outdir="out"): 38 | hphpath = os.path.splitext(hpbpath)[0] + ".hph" 39 | inname = os.path.basename(os.path.splitext(hpbpath)[0]) 40 | with open(hphpath, "rb") as fp: 41 | hphbuf = fp.read() 42 | with open(hpbpath, "rb") as fp: 43 | hpbbuf = memoryview(fp.read()) 44 | if not os.path.exists(outdir): 45 | os.makedirs(outdir) 46 | 47 | hpc_header = hpac_header_t.from_buffer_copy(hphbuf) 48 | assert(hpc_header.id == int.from_bytes(b"HPAC", "little", signed=False)) 49 | print(f"[extract_hpb] inpath={hpbpath} outdir={outdir} count={hpc_header.count}") 50 | for i in range(hpc_header.count): 51 | offset = ctypes.sizeof(hpac_header_t) + i*ctypes.sizeof(hpac_entry_t) 52 | hpac_entry = hpac_entry_t.from_buffer_copy(hphbuf, offset) 53 | if hpac_entry.fileSize == 0: continue 54 | print(f"[extract_hpb] no={i} offset=0x{hpac_entry.offset:08x}" 55 | f" fileSize=0x{hpac_entry.fileSize:08x} meltSize=0x{hpac_entry.meltSize:08x}" 56 | f" fileCRC={hpac_entry.fileCRC:08x} meltCRC={hpac_entry.meltCRC:08x}") 57 | inbuf = hpbbuf[hpac_entry.offset: hpac_entry.offset + hpac_entry.fileSize] 58 | outbuf = inbuf 59 | assert(crc32(inbuf) == hpac_entry.fileCRC) 60 | if inbuf[0:4] == b'HLZS': outbuf = decode_hlzs(inbuf) 61 | assert(len(outbuf) == hpac_entry.meltSize) 62 | assert(crc32(outbuf) == hpac_entry.meltCRC) 63 | outpath = os.path.join(outdir, inname + f"_{hpac_entry.offset:08x}") 64 | with open(outpath, "wb") as fp: 65 | fp.write(outbuf) 66 | 67 | def main(argv): 68 | if len(argv) < 2: 69 | print("hunex_hpb inpath [outdir]") 70 | return 71 | inpath = argv[1] 72 | outdir = os.path.splitext(inpath)[0] + "_extract" if len(argv) < 3 else argv[2] 73 | extract_hpb(inpath, outdir) 74 | 75 | if __name__ == "__main__": 76 | main(sys.argv) 77 | -------------------------------------------------------------------------------- /project/ig/ig_redirect.mk: -------------------------------------------------------------------------------- 1 | CC:=clang 2 | BUILD_DIR:=asset/build 3 | INCS:=-Isrc/compat 4 | LIBDIRS:=-Lcompat 5 | LIBS:=-luser32 -lgdi32 -lshlwapi -ladvapi32 6 | CFLAGS:=-ffunction-sections -fdata-sections -DUSE_COMPAT 7 | LDFLAGS:= 8 | 9 | ifdef DEBUG 10 | CFLAGS+=-g -D_DEBUG 11 | else 12 | CFLAGS+=-Os 13 | endif 14 | 15 | ifneq (,$(findstring clang, $(CC))) 16 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 17 | LDFLAGS+=-Wl,/OPT:REF 18 | else 19 | CFLAGS+=-m32 20 | ifneq (,$(findstring gcc, $(CC))) 21 | LDFLAGS+= -Wl,--gc-sections\ 22 | -static-libgcc -static-libstdc++ \ 23 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 24 | -Wl,--no-whole-archive 25 | endif 26 | endif 27 | 28 | all: prepare ig_redirect 29 | 30 | prepare: 31 | @if ! [ -d $(BUILD_DIR) ]; then mkdir -p $(BUILD_DIR); fi 32 | 33 | ig_redirect: src/ig_redirect.c 34 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 35 | -D USE_COMPAT \ 36 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 37 | rm -rf $(BUILD_DIR)/$@.exp 38 | rm -rf $(BUILD_DIR)/$@.lib 39 | rm -rf $(BUILD_DIR)/$@.def 40 | 41 | .PHONY: prepare ig_redirect -------------------------------------------------------------------------------- /project/ig/src/flowers1_pc_dumpscript.py: -------------------------------------------------------------------------------- 1 | import frida 2 | import sys 3 | """ 4 | this is from flowers1 spring script1.dll, put that dll to other games plugin folders 5 | sub_1001A340 //load script 6 | 1001A504 | 837C24 50 1 | cmp dword ptr ss:[esp + 50], 10 | [ebp+1ff4] text_buffer, esi length, [esp+3C] script name 7 | 1001A509 | 8BB5 F41F00 | mov esi, dword ptr ss:[ebp + 1FF4] | 8 | 1001A50F | 89B5 F81F00 | mov dword ptr ss:[ebp + 1FF8], esi | [ebp+1FF8]:"script/01a_00001.s" 9 | 1001A515 | 89B5 FC1F00 | mov dword ptr ss:[ebp + 1FFC], esi | 10 | 1001A51B | 89B5 002000 | mov dword ptr ss:[ebp + 2000], esi | [ebp+2000]:"script/01a_00001.s" 11 | 1001A521 | 72 0D | jb script.1001A530 12 | """ 13 | 14 | jscode = """ 15 | 'use strict'; 16 | var g_null_count = 0; 17 | var scriptdll = Process.findModuleByName('Script.dll'); 18 | var hook_script_offset = 0x1A504; 19 | var load_script_offset = 0x1A340; 20 | var hook_script_ptr = scriptdll.base.add(hook_script_offset); 21 | var load_script_ptr = scriptdll.base.add(load_script_offset); 22 | 23 | // hook script method 24 | console.log(scriptdll.name, scriptdll.base); 25 | console.log("hooked text at ", hook_script_ptr); 26 | Interceptor.attach(hook_script_ptr, { 27 | onEnter: function (args) { 28 | console.log("In hook_text_offset"); 29 | var script_addr = this.context.ebp.add(0x1FF4).readPointer(); 30 | var script_length = this.context.esi.toInt32(); 31 | var script_data = script_addr.readByteArray(script_length); 32 | var name = "null"; 33 | try { 34 | var name_addr = this.context.esp.add(0x3C).readPointer(); 35 | name = name_addr.readCString(); 36 | name = name.split('/')[name.split('/').length - 1]; 37 | } 38 | catch (e) { 39 | console.log(e.message); 40 | name = "null" + g_null_count.toString() + ".s"; 41 | g_null_count++; 42 | } 43 | console.log(name, "script_addr:", script_addr, "length:", script_length); 44 | 45 | var file = new File(name, "wb"); 46 | file.write(script_data); 47 | file.close(); 48 | } 49 | }) 50 | 51 | // to decrypt scripts 52 | var g_buf = Memory.alloc(0x10000); 53 | var g_buf_name = Memory.alloc(256); 54 | var load_script = new NativeFunction(load_script_ptr, 'void', ['pointer', 'pointer'], 'fastcall'); 55 | console.log("load_script_func at:", load_script_ptr) 56 | 57 | var op = recv('filelist', function(v){ 58 | var filelist = v.payload; 59 | for (var i in filelist){ 60 | console.log(i, filelist[i], "to be dumped...") 61 | g_buf_name.writeAnsiString(filelist[i]); 62 | load_script(g_buf, g_buf_name); 63 | } 64 | }); 65 | """ 66 | 67 | def on_message(message, data): 68 | print(message, data) 69 | 70 | def main(): 71 | print("dump_flowers_script [flowers_exepath] [filelistpath]") 72 | filelist = [] 73 | if len(sys.argv) < 2: process_name = "FLOWERS_CHS.exe" 74 | else: process_name = sys.argv[1] 75 | if len(sys.argv) >= 3: 76 | with open(sys.argv[2], 'r') as fp: 77 | for line in fp.readlines(): 78 | filelist.append(line.strip('\n').strip('\r')) 79 | 80 | session = frida.attach(process_name) 81 | script = session.create_script(jscode) 82 | script.on('message', on_message) 83 | script.load() 84 | script.post({'type':'filelist', 'payload':filelist}) 85 | sys.stdin.read() 86 | 87 | if __name__ == "__main__": 88 | main() -------------------------------------------------------------------------------- /project/ig/src/flowers2_pc_dumpscript.py: -------------------------------------------------------------------------------- 1 | import frida 2 | import sys 3 | """ 4 | this is for flowers2 summer, only the offset is changed. 5 | sub_10019EE0(int a1, void *a2) 6 | 7 | 1001A0A2 | 72 EC | jb script.1001A090 | 8 | 1001A0A4 | 837C24 50 1 | cmp dword ptr ss:[esp + 50], 10 | 9 | 1001A0A9 | 8BB5 D82100 | mov esi, dword ptr ss:[ebp + 21D8] | [ebp + 21d8] is the buffer 10 | 1001A0AF | 89B5 DC2100 | mov dword ptr ss:[ebp + 21DC], esi | 11 | 1001A0B5 | 89B5 E02100 | mov dword ptr ss:[ebp + 21E0], esi | 12 | 1001A0BB | 89B5 E42100 | mov dword ptr ss:[ebp + 21E4], esi | 13 | 1001A0C1 | 72 0D | jb script.1001A0D0 | 14 | 1001A0C3 | 8B4424 3C | mov eax, dword ptr ss:[esp + 3C] | [esp+3C]:"script/02a_00001.s" 15 | 16 | """ 17 | 18 | jscode = """ 19 | 'use strict'; 20 | var g_null_count = 0; 21 | var scriptdll = Process.findModuleByName('Script.dll'); 22 | var hook_script_offset = 0x1A0A4; 23 | var load_script_offset = 0x19EE0; 24 | var hook_script_ptr = scriptdll.base.add(hook_script_offset); 25 | var load_script_ptr = scriptdll.base.add(load_script_offset); 26 | 27 | // hook script method 28 | console.log(scriptdll.name, scriptdll.base); 29 | console.log("hooked text at ", hook_script_ptr); 30 | Interceptor.attach(hook_script_ptr, { 31 | onEnter: function (args) { 32 | console.log("In hook_text_offset"); 33 | var script_addr = this.context.ebp.add(0x21D8).readPointer(); 34 | var script_length = this.context.esi.toInt32(); 35 | var script_data = script_addr.readByteArray(script_length); 36 | var name = "null"; 37 | try { 38 | var name_addr = this.context.esp.add(0x3C).readPointer(); 39 | name = name_addr.readCString(); 40 | name = name.split('/')[name.split('/').length - 1]; 41 | } 42 | catch (e) { 43 | console.log(e.message); 44 | name = "null" + g_null_count.toString() + ".s"; 45 | g_null_count++; 46 | } 47 | console.log(name, "script_addr:", script_addr, "length:", script_length); 48 | 49 | var file = new File(name, "wb"); 50 | file.write(script_data); 51 | file.close(); 52 | } 53 | }) 54 | 55 | // to decrypt scripts 56 | var g_buf = Memory.alloc(0x10000); 57 | var g_buf_name = Memory.alloc(256); 58 | var load_script = new NativeFunction(load_script_ptr, 'void', ['pointer', 'pointer'], 'fastcall'); 59 | console.log("load_script_func at:", load_script_ptr) 60 | 61 | var op = recv('filelist', function(v){ 62 | var filelist = v.payload; 63 | for (var i in filelist){ 64 | console.log(i, filelist[i], "to be dumped...") 65 | g_buf_name.writeAnsiString(filelist[i]); 66 | load_script(g_buf, g_buf_name); 67 | } 68 | }); 69 | """ 70 | 71 | def on_message(message, data): 72 | print(message, data) 73 | 74 | def main(): 75 | print("dump_flowers_script [flowers_exepath] [filelistpath]") 76 | filelist = [] 77 | if len(sys.argv) < 2: process_name = "FLOWERS2_CHS.exe" 78 | else: process_name = sys.argv[1] 79 | if len(sys.argv) >= 3: 80 | with open(sys.argv[2], 'r') as fp: 81 | for line in fp.readlines(): 82 | filelist.append(line.strip('\n').strip('\r')) 83 | 84 | session = frida.attach(process_name) 85 | script = session.create_script(jscode) 86 | script.on('message', on_message) 87 | script.load() 88 | script.post({'type':'filelist', 'payload':filelist}) 89 | sys.stdin.read() 90 | 91 | if __name__ == "__main__": 92 | main() -------------------------------------------------------------------------------- /project/ig/src/flowers3_pc_dumpscript.py: -------------------------------------------------------------------------------- 1 | import frida 2 | import sys 3 | """ 4 | this is for flowers3 autumn, only the offset is changed. 5 | sub_1001A2F0(int a1, void *a2) 6 | 7 | .text:1001A4A0 mov ecx, [ebp+21DCh] 8 | .text:1001A4A6 mov dl, [ecx+eax] 9 | .text:1001A4A9 add ecx, eax 10 | .text:1001A4AB inc eax 11 | .text:1001A4AC not dl 12 | .text:1001A4AE mov [ecx], dl 13 | .text:1001A4B0 cmp eax, esi 14 | .text:1001A4B2 jb short loc_1001A4A0 15 | .text:1001A4B4 16 | .text:1001A4B4 loc_1001A4B4: ; CODE XREF: sub_1001A2F0+1AB↑j 17 | .text:1001A4B4 cmp [esp+64h+var_14], 10h 18 | .text:1001A4B9 mov esi, [ebp+21DCh] 19 | .text:1001A4BF mov [ebp+21E0h], esi 20 | .text:1001A4C5 mov [ebp+21E4h], esi 21 | .text:1001A4CB mov [ebp+21E8h], esi 22 | .text:1001A4D1 jb short loc_1001A4E0 23 | .text:1001A4D3 mov eax, [esp+64h+Src] 24 | .text:1001A4D7 push eax ; void * 25 | .text:1001A4D8 call ??3@YAXPAX@Z ; operator delete(void *) 26 | .text:1001A4DD add esp, 4 27 | """ 28 | 29 | jscode = """ 30 | 'use strict'; 31 | var g_null_count = 0; 32 | var scriptdll = Process.findModuleByName('Script.dll'); 33 | var hook_script_offset = 0x1A4B4; 34 | var load_script_offset = 0x1A2F0; 35 | var hook_script_ptr = scriptdll.base.add(hook_script_offset); 36 | var load_script_ptr = scriptdll.base.add(load_script_offset); 37 | 38 | // hook script method 39 | console.log(scriptdll.name, scriptdll.base); 40 | console.log("hooked text at ", hook_script_ptr); 41 | Interceptor.attach(hook_script_ptr, { 42 | onEnter: function (args) { 43 | console.log("In hook_text_offset"); 44 | var script_addr = this.context.ebp.add(0x21DC).readPointer(); 45 | var script_length = this.context.esi.toInt32(); 46 | var script_data = script_addr.readByteArray(script_length); 47 | var name = "null"; 48 | try { 49 | var name_addr = this.context.esp.add(0x3C).readPointer(); 50 | name = name_addr.readCString(); 51 | name = name.split('/')[name.split('/').length - 1]; 52 | } 53 | catch (e) { 54 | console.log(e.message); 55 | name = "null" + g_null_count.toString() + ".s"; 56 | g_null_count++; 57 | } 58 | console.log(name, "script_addr:", script_addr, "length:", script_length); 59 | 60 | var file = new File(name, "wb"); 61 | file.write(script_data); 62 | file.close(); 63 | } 64 | }) 65 | 66 | // to decrypt scripts 67 | var g_buf = Memory.alloc(0x10000); 68 | var g_buf_name = Memory.alloc(256); 69 | var load_script = new NativeFunction(load_script_ptr, 'void', ['pointer', 'pointer'], 'fastcall'); 70 | console.log("load_script_func at:", load_script_ptr) 71 | 72 | var op = recv('filelist', function(v){ 73 | var filelist = v.payload; 74 | for (var i in filelist){ 75 | console.log(i, filelist[i], "to be dumped...") 76 | g_buf_name.writeAnsiString(filelist[i]); 77 | load_script(g_buf, g_buf_name); 78 | } 79 | }); 80 | """ 81 | 82 | def on_message(message, data): 83 | print(message, data) 84 | 85 | def main(): 86 | print("dump_flowers_script [flowers_exepath] [filelistpath]") 87 | filelist = [] 88 | if len(sys.argv) < 2: process_name = "FLOWERS3_CHS.exe" 89 | else: process_name = sys.argv[1] 90 | if len(sys.argv) >= 3: 91 | with open(sys.argv[2], 'r') as fp: 92 | for line in fp.readlines(): 93 | filelist.append(line.strip('\n').strip('\r')) 94 | 95 | session = frida.attach(process_name) 96 | script = session.create_script(jscode) 97 | script.on('message', on_message) 98 | script.load() 99 | script.post({'type':'filelist', 'payload':filelist}) 100 | sys.stdin.read() 101 | 102 | if __name__ == "__main__": 103 | main() -------------------------------------------------------------------------------- /project/ig/src/flowers_pc_mergetext.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import codecs 4 | 5 | def merge_chsjp_text(jpdir, chsdir, outdir): 6 | errlines = [] 7 | errfilepath = os.path.join(outdir, "err.txt") 8 | for file in os.listdir(jpdir): 9 | if os.path.splitext(file)[1] != '.txt': continue 10 | print(file) 11 | jplines = [] 12 | chslines = [] 13 | with open(os.path.join(jpdir, file), 'rb') as fp: 14 | data = fp.read() 15 | i = 0 16 | while i < len(data): 17 | end = data.find(b'\n', i) 18 | if end==-1: end = len(data) 19 | line_data = data[i:end+1] 20 | try: 21 | line = line_data.decode('sjis') 22 | except: 23 | print(hex(i)) 24 | line_data = line_data.replace(b'\x87\x81', b'\x81\x68') 25 | line_data = line_data.replace(b'\x87\x80', b'\x81\x67') 26 | line_data = line_data.replace(b'\x9c\xff', b'\x81\x40') 27 | # line_data = re.sub(b'\x87.', '・'.encode('sjis'), line_data) 28 | line = line_data.decode('sjis') 29 | jplines.append(line) 30 | i = end + 1 31 | with codecs.open(os.path.join(chsdir, file), 'r', 'gbk') as fp: 32 | i = 0 33 | errlines.append(file + " chs\n") 34 | try: 35 | line = fp.readline() 36 | except UnicodeDecodeError: 37 | line = "#UNICODE_ERR" 38 | errlines.append("#"+str(i)+"\n") 39 | while line: 40 | chslines.append(line) 41 | try: 42 | line = fp.readline() 43 | except UnicodeDecodeError: 44 | line = "#UNICODE_ERR" 45 | errlines.append("#"+str(i)+"\n") 46 | i += 1 47 | with codecs.open(os.path.join(outdir, file), 'w', 'utf-8') as fp: 48 | for i, (jpline, chsline) in enumerate(zip(jplines, chslines)): 49 | jpline = jpline.strip('\n').strip('\r') 50 | chsline = chsline.strip('\n').strip('\r') 51 | 52 | chsline = chsline.replace("仈", "#") 53 | chsline = chsline.replace("亹", "$") 54 | 55 | chsline = chsline.replace("偅", "。") 56 | chsline = chsline.replace("偂", ",") 57 | chsline = chsline.replace("偉", "、") 58 | chsline = chsline.replace("僅", "”") 59 | chsline = chsline.replace("偭", "》") 60 | chsline = chsline.replace("僁", "?") 61 | chsline = chsline.replace("傿", "!") 62 | chsline = chsline.replace("偋", "」") 63 | chsline = chsline.replace("偐", "』") 64 | chsline = chsline.replace("傽", ")") 65 | 66 | fstr1 = "○{idx:04}○ {text}\n" 67 | fstr2 = fstr1.replace('○', '●')+"\n" 68 | fp.write(fstr1.format(idx=i, text=jpline)) 69 | fp.write(fstr2.format(idx=i, text=chsline)) 70 | # with open(errfilepath, "w") as fp: 71 | # fp.writelines(errlines) 72 | print(file+", "+ str(len(jplines))+" merged!") 73 | 74 | def debug(): 75 | pass 76 | 77 | def main(): 78 | if len(sys.argv) < 2: 79 | print("merge_chsjp_text jpdir chsdir outdir") 80 | merge_chsjp_text(sys.argv[1], sys.argv[2], sys.argv[3]) 81 | 82 | if __name__ == "__main__": 83 | # debug() 84 | main() 85 | pass 86 | -------------------------------------------------------------------------------- /project/kid/src/kid_psp_bip2.py: -------------------------------------------------------------------------------- 1 | """ 2 | encode or decode bip files (lzss compress), using cffi 3 | v0.1, developed by devseed 4 | 5 | tested games: 6 | ULJM06002 想いのかけら -Close to- 7 | """ 8 | 9 | import os 10 | import sys 11 | import struct 12 | from mmap import mmap, ACCESS_READ, ACCESS_COPY 13 | from typing import List 14 | 15 | import shutil 16 | import tempfile 17 | from cffi import FFI 18 | 19 | try: 20 | import pylzss 21 | except ImportError: 22 | ffi = FFI() 23 | ffi.cdef(""" 24 | int lzss_decode(uint8_t *dst, uint8_t *src, uint32_t srclen); 25 | uint8_t *lzss_encode(uint8_t *dst, uint32_t dstlen, uint8_t *src, uint32_t srcLen); 26 | """) 27 | 28 | curdir = os.path.dirname(os.path.abspath(__file__)) 29 | ffi.set_source("pylzss", """ 30 | #include "lzss.h" 31 | """, include_dirs=[curdir]) 32 | tmpdir = tempfile.TemporaryDirectory() 33 | pydpath = ffi.compile(tmpdir.name, verbose=True) 34 | shutil.copy(pydpath, curdir) 35 | tmpdir.cleanup() 36 | import pylzss 37 | 38 | def decode_bip(data: memoryview, outpath=None): 39 | ffi = FFI() 40 | zsize = len(data) - 4 41 | rawsize: int = struct.unpack_from(" 3 else "OUT" 95 | export_cdar(sys.argv[2], outdir) 96 | elif sys.argv[1].lower() == 'i': 97 | outdir = sys.argv[4] if len(sys.argv) > 4 else "OUT.DAR" 98 | import_cdar(sys.argv[2], sys.argv[3], outdir) 99 | else: raise NotImplementedError( 100 | f"unknow type {sys.argv[1]}") 101 | 102 | if __name__ == "__main__": 103 | #debug() 104 | main() 105 | pass -------------------------------------------------------------------------------- /project/krkr/krkrtool.mk: -------------------------------------------------------------------------------- 1 | # make -f krkrtool.mk CXX=/opt/llvm-mingw/bin/i686-w64-mingw32-clang++ # llvm 18.1.8 2 | # make -f krkrtool.mk CXX=i686-w64-mingw32-gcc++ # gcc 12 3 | 4 | CXX:=clang++ 5 | BUILD_DIR:=asset/build 6 | INCS:=-Isrc/compat 7 | LIBS:=-lgdi32 8 | CFLAGS:=-ffunction-sections -fdata-sections -Wno-null-dereference 9 | LDFLAGS:= 10 | 11 | ifdef DEBUG 12 | CFLAGS+=-g -D_DEBUG 13 | else 14 | CFLAGS+=-Os 15 | endif 16 | ifneq (,$(wildcard src/compat/*)) 17 | CFLAGS+=-DUSECOMPAT 18 | endif 19 | 20 | ifneq (,$(findstring clang++, $(CXX))) # for llvm-mingw 21 | CFLAGS+=-m32 -static-libstdc++ \ 22 | -Wl,-Bstatic,--whole-archive -lunwind \ 23 | -Wl,--no-whole-archive \ 24 | -gcodeview -Wl,--pdb=$(BUILD_DIR)/version.pdb 25 | LDFLAGS+= -Wl,--gc-sections 26 | else ifneq (,$(findstring g++, $(CXX))) # for mingw-w64 27 | CFLAGS+=-m32 28 | LDFLAGS+= -Wl,--gc-sections \ 29 | -static-libgcc -static-libstdc++ \ 30 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 31 | -Wl,--no-whole-archive 32 | else ifneq (,$(findstring tcc, $(CXX))) # for tcc 33 | $(error not support tcc for compile cpp) 34 | CFLAGS+=-m32 35 | else # for previous llvm clang with msvc 36 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 37 | LDFLAGS+=-Wl,/OPT:REF # for llvm 38 | endif 39 | 40 | all: prepare krkr_hxv4_dumphash krkr_hxv4_patch 41 | 42 | prepare: 43 | @mkdir -p $(BUILD_DIR) 44 | 45 | krkr_hxv4_dumphash: src/krkr_hxv4_dumphash.cpp src/compat/tp_stub.cpp src/compat/winversion_v100.def 46 | @echo "## $@" 47 | $(CXX) -shared $^ -o$(BUILD_DIR)/version.dll \ 48 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 49 | @cp -f $(BUILD_DIR)/version.dll $(BUILD_DIR)/$@.dll 50 | @if [ -f $(BUILD_DIR)/version.pdb ]; then cp -f $(BUILD_DIR)/version.pdb $(BUILD_DIR)/$@.pdb; fi 51 | @rm -rf $(BUILD_DIR)/version.* 52 | 53 | krkr_hxv4_patch: src/krkr_hxv4_patch.cpp src/compat/tp_stub.cpp src/compat/winversion_v100.def 54 | @echo "## $@" 55 | $(CXX) -shared $^ -o$(BUILD_DIR)/version.dll \ 56 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 57 | @cp -f $(BUILD_DIR)/version.dll $(BUILD_DIR)/$@.dll 58 | @if [ -f $(BUILD_DIR)/version.pdb ]; then cp -f $(BUILD_DIR)/version.pdb $(BUILD_DIR)/$@.pdb; fi 59 | @rm -rf $(BUILD_DIR)/version.* 60 | 61 | .PHONY: prepare krkr_hxv4_dumphash krkr_hxv4_patch -------------------------------------------------------------------------------- /project/krkr/sdhime.mk: -------------------------------------------------------------------------------- 1 | BUILD_DIR:=asset/build 2 | INCS:= 3 | LIBDIRS:= 4 | LIBS:=-luser32 -lgdi32 5 | CFLAGS:=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE # -D_DEBUG -g 6 | 7 | all: sdhime_patch sdhime_xp3enc 8 | 9 | sdhime_patch: src/sdhime_patch.c 10 | clang -shared $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $^ -o $(BUILD_DIR)/$@.dll -Os 11 | rm -rf $(BUILD_DIR)/$@.exp 12 | rm -rf $(BUILD_DIR)/$@.lib 13 | 14 | sdhime_xp3enc: src/sdhime_xp3enc.cpp 15 | clang -shared $^ -o $(BUILD_DIR)/$@.dll $(CFLAGS) -Wl,"/DEF:src/sdhime_xp3enc.def" 16 | rm -rf $(BUILD_DIR)/$@.exp 17 | rm -rf $(BUILD_DIR)/$@.lib 18 | 19 | .PHONY: sdhime_patch, sdhime_xp3enc -------------------------------------------------------------------------------- /project/krkr/src/compat/winversion_v100.def: -------------------------------------------------------------------------------- 1 | LIBRARY "version" 2 | EXPORTS 3 | GetFileVersionInfoA = __wrap_GetFileVersionInfoA 4 | GetFileVersionInfoByHandle = __wrap_GetFileVersionInfoByHandle 5 | GetFileVersionInfoExA = __wrap_GetFileVersionInfoExA 6 | GetFileVersionInfoExW = __wrap_GetFileVersionInfoExW 7 | GetFileVersionInfoSizeA = __wrap_GetFileVersionInfoSizeA 8 | GetFileVersionInfoSizeExA = __wrap_GetFileVersionInfoSizeExA 9 | GetFileVersionInfoSizeExW = __wrap_GetFileVersionInfoSizeExW 10 | GetFileVersionInfoSizeW = __wrap_GetFileVersionInfoSizeW 11 | GetFileVersionInfoW = __wrap_GetFileVersionInfoW 12 | VerFindFileA = __wrap_VerFindFileA 13 | VerFindFileW = __wrap_VerFindFileW 14 | VerInstallFileA = __wrap_VerInstallFileA 15 | VerInstallFileW = __wrap_VerInstallFileW 16 | VerLanguageNameA = __wrap_VerLanguageNameA 17 | VerLanguageNameW = __wrap_VerLanguageNameW 18 | VerQueryValueA = __wrap_VerQueryValueA 19 | VerQueryValueW = __wrap_VerQueryValueW -------------------------------------------------------------------------------- /project/krkr/src/compat/winversion_v100.h: -------------------------------------------------------------------------------- 1 | /** 2 | * windows version dll proxy, together with winversion.def 3 | * v0.1, developed by devseed 4 | * 5 | */ 6 | 7 | #ifndef _WINVERSION_H 8 | #define _WINVERSION_H 9 | #include 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | #define WIVERSION_VERSION 100 14 | 15 | #ifdef USECOMPAT 16 | #include "commdef_v110.h" 17 | #else 18 | #include "commdef.h" 19 | #endif // USECOMPAT 20 | 21 | // macro and global declear 22 | static HMODULE s_winversion = NULL; 23 | #if defined(_MSC_VER) 24 | // https://github.com/BitCrackers/version-proxy/blob/main/src/version.cpp 25 | #ifdef _M_AMD64 // msvc x64 26 | #pragma warning (disable: 4081) 27 | #define STRINGIFY(name) #name 28 | #define EXPORT_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) 29 | #define WINVERSION_WRAP_FUNC(name) \ 30 | FARPROC s_##name; \ 31 | __declspec(dllexport) void WINAPI __wrap_##name() \ 32 | { \ 33 | __pragma(STRINGIFY(EXPORT_FUNCTION)); \ 34 | s_##name(); \ 35 | } 36 | #else // msvc x86 37 | #define WINVERSION_WRAP_FUNC(name) \ 38 | static FARPROC s_##name; \ 39 | __declspec(naked) void __wrap_##name() \ 40 | { \ 41 | __asm jmp[s_##name] \ 42 | } 43 | #endif 44 | #else // gcc 45 | #define WINVERSION_WRAP_FUNC(name) \ 46 | static FARPROC s_##name = NULL; \ 47 | EXPORT NAKED void __wrap_##name () \ 48 | {\ 49 | asm volatile("jmp *%0" : : "m" (s_##name)); \ 50 | } 51 | 52 | #endif // _MSC_VER 53 | #define WINVERSION_BIND_FUNC(name) s_##name = GetProcAddress(s_winversion, #name); 54 | 55 | // export function define 56 | WINVERSION_WRAP_FUNC(GetFileVersionInfoA) 57 | WINVERSION_WRAP_FUNC(GetFileVersionInfoByHandle) 58 | WINVERSION_WRAP_FUNC(GetFileVersionInfoExW) 59 | WINVERSION_WRAP_FUNC(GetFileVersionInfoExA) 60 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeA) 61 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeExW) 62 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeExA) 63 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeW) 64 | WINVERSION_WRAP_FUNC(GetFileVersionInfoW) 65 | WINVERSION_WRAP_FUNC(VerFindFileA) 66 | WINVERSION_WRAP_FUNC(VerFindFileW) 67 | WINVERSION_WRAP_FUNC(VerInstallFileA) 68 | WINVERSION_WRAP_FUNC(VerInstallFileW) 69 | WINVERSION_WRAP_FUNC(VerLanguageNameA) 70 | WINVERSION_WRAP_FUNC(VerLanguageNameW) 71 | WINVERSION_WRAP_FUNC(VerQueryValueA) 72 | WINVERSION_WRAP_FUNC(VerQueryValueW) 73 | 74 | static void winversion_init() 75 | { 76 | // origin version path 77 | char versionpath[MAX_PATH]; 78 | GetSystemDirectoryA(versionpath, MAX_PATH); 79 | strcat(versionpath, "\\version.dll"); 80 | s_winversion = LoadLibraryA(versionpath); 81 | 82 | // bind version apis 83 | WINVERSION_BIND_FUNC(GetFileVersionInfoA); 84 | WINVERSION_BIND_FUNC(GetFileVersionInfoByHandle); 85 | WINVERSION_BIND_FUNC(GetFileVersionInfoExW); 86 | WINVERSION_BIND_FUNC(GetFileVersionInfoExA); 87 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeA); 88 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeExW); 89 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeExA); 90 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeW); 91 | WINVERSION_BIND_FUNC(GetFileVersionInfoW); 92 | WINVERSION_BIND_FUNC(VerFindFileA); 93 | WINVERSION_BIND_FUNC(VerFindFileW); 94 | WINVERSION_BIND_FUNC(VerInstallFileA); 95 | WINVERSION_BIND_FUNC(VerInstallFileW); 96 | WINVERSION_BIND_FUNC(VerLanguageNameA); 97 | WINVERSION_BIND_FUNC(VerLanguageNameW); 98 | WINVERSION_BIND_FUNC(VerQueryValueA); 99 | WINVERSION_BIND_FUNC(VerQueryValueW); 100 | } 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | #endif -------------------------------------------------------------------------------- /project/krkr/src/krkr_text.py: -------------------------------------------------------------------------------- 1 | """ 2 | batch convert the text encoding for krkr 3 | v0.2, developed by devseed 4 | """ 5 | 6 | import os 7 | import sys 8 | import fnmatch 9 | import argparse 10 | 11 | def convert_file(inapth, outpath, fromcode, tocode, ignore="from", newline: str="") -> bool: 12 | _fromcode = fromcode.replace("-bom", "") 13 | _tocode = tocode.replace("-bom", "") 14 | ignore_from = ignore == "form" or ignore == "both" 15 | ignore_to = ignore == "to" or ignore == "both" 16 | outdir = os.path.dirname(outpath) 17 | if not os.path.exists(outdir) and len(outdir) > 0: os.makedirs(outdir) 18 | 19 | with open(inapth, "r", encoding=_fromcode, newline=None, 20 | errors="ignore" if ignore_from else "strict") as fp: 21 | try: 22 | lines = fp.readlines() 23 | except UnicodeDecodeError as e: 24 | return False 25 | 26 | if len(lines) > 0 and len(lines[0]) > 0: 27 | lines[0] = lines[0].lstrip('\ufeff') 28 | 29 | with open(outpath, "w", encoding=_tocode, newline=newline, 30 | errors="ignore" if ignore_to else "strict") as fp: 31 | try: 32 | if "bom" in tocode: fp.write('\ufeff') 33 | fp.writelines(lines) 34 | except UnicodeEncodeError as e: 35 | return False 36 | 37 | return True 38 | 39 | def convert_dir(indir, outdir, fromcode, tocode, 40 | ignore="from", newline="", includes=None, excludes=None) -> int: 41 | count = 0 42 | for root, dirs, files in os.walk(indir): 43 | for file in files: 44 | inpath = os.path.join(root, file) 45 | relpath = os.path.relpath(inpath, indir) 46 | outpath = os.path.join(outdir, relpath) 47 | include_flag = True 48 | if excludes is not None: 49 | for t in excludes: 50 | if not fnmatch.fnmatch(relpath, t): continue # match glob 51 | include_flag = False 52 | break 53 | if includes is not None: 54 | include_flag = False 55 | for t in includes: 56 | if not fnmatch.fnmatch(relpath, t): continue 57 | include_flag = True 58 | break 59 | if not include_flag: continue 60 | if convert_file(inpath, outpath, 61 | fromcode, tocode, ignore=ignore, newline=newline): 62 | count += 1 63 | print(f"CONVERT {relpath}") 64 | else: 65 | if os.path.exists(outpath): os.remove(outpath) 66 | print(f"FAILED {relpath}") 67 | return count 68 | 69 | def cli(cmdstr=None): 70 | parser = argparse.ArgumentParser(description="batch convert text encoding, v0.2, developed by devseed") 71 | parser.add_argument("inpath", help="file or directory") 72 | parser.add_argument("-o", "--outpath", default="out", help="file or directory") 73 | parser.add_argument("-f", "--from-code", metavar="encoding", default="sjis") 74 | parser.add_argument("-t", "--to-code", metavar="encoding", default="utf16-bom") 75 | parser.add_argument("-n", "--ignore", choices=["none", "from", "to", "both"], default="from", help="ignore coding error") 76 | parser.add_argument("-l", "--newline", choices=["origin", "lf", "crlf", "cr"], default="origin", help="change line encoding") 77 | parser.add_argument("-i", "--include", action="append", default=None, help="include pattern, such as *.txt") 78 | parser.add_argument("-e", "--exclude", action="append", default=None, help="exclude pattern, such as *.png") 79 | 80 | if cmdstr is None and len(sys.argv) < 2: 81 | parser.print_help() 82 | return 83 | 84 | args = parser.parse_args(cmdstr.split(' ') if cmdstr else None) 85 | print(args) 86 | 87 | newline = "" 88 | if args.newline.lower() == "origin": newline = "" 89 | elif args.newline.lower() == "cr": newline = "\r" 90 | elif args.newline.lower() == "lf": newline = "\n" 91 | elif args.newline.lower() == "crlf": newline = "\r\n" 92 | inpath, outpath = args.inpath, args.outpath 93 | fromcode, tocode = args.from_code, args.to_code 94 | ignore = args.ignore 95 | includes, excludes = args.include, args.exclude 96 | 97 | if not os.path.exists(inpath): 98 | raise FileExistsError(f"{inpath} is invalid") 99 | if os.path.isfile(inpath): 100 | res = convert_file(inpath, outpath, fromcode, tocode, ignore=ignore, newline=newline) 101 | print(f'{"CONVERT" if res else "FAILED"} {os.path.basename(inpath)}') 102 | else: convert_dir(inpath, outpath, fromcode, tocode, 103 | ignore=ignore, newline=newline, includes=includes, excludes=excludes) 104 | 105 | if __name__ == "__main__": 106 | cli() 107 | 108 | """ history 109 | v0.1, krkr_sjis2utf16 110 | v0.2, remake with new cli and add more options 111 | """ -------------------------------------------------------------------------------- /project/krkr/src/sdhime_xp3enc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) 4 | { 5 | // DLL エントリポイント 6 | return 1; 7 | } 8 | 9 | extern "C" void __stdcall XP3ArchiveAttractFilter_v2( 10 | unsigned __int32 hash, 11 | unsigned __int64 offset, void * buffer, long bufferlen) 12 | { 13 | // バージョン 2 関数は以下の引数を受け取ります。 14 | // hash : 入力ファイルの(暗号化解除時の)32bitハッシュです。 15 | // offset : "buffer" 引数が示すデータが、ファイルの先頭から何バイト目 16 | // であるか (ファイルが圧縮される場合、無圧縮の状態のバイト 17 | // オフセットです ) 18 | // buffer : 対象となるデータです。ファイルが圧縮される場合は、圧縮され 19 | // る前のデータです。 20 | // ( ファイルが圧縮された後のデータにこの関数で変更を加えるこ 21 | // とは出来ません ) 22 | // bufferlen : "buffer" 引数が表すデータの長さです。 23 | 24 | // しかしここではサンプルとして、hash の最下位バイトを XOR する方法を 25 | // 示します。 26 | 27 | int i; 28 | for(i = 0; i < bufferlen; i++) 29 | { 30 | 31 | unsigned char k = (hash + 1) & 0xff; 32 | ((unsigned char*)buffer)[i] = (~((unsigned char*)buffer)[i] ^ k); 33 | } 34 | } -------------------------------------------------------------------------------- /project/krkr/src/sdhime_xp3enc.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | XP3ArchiveAttractFilter_v2 -------------------------------------------------------------------------------- /project/livemaker/aikimi.mk: -------------------------------------------------------------------------------- 1 | CC:=clang 2 | BUILD_DIR:=asset/build 3 | SRC_DIR:=src 4 | INCS:=-I$(SRC_DIR)/compat 5 | LIBDIRS:=-L$(SRC_DIR)/compat 6 | LIBS:=-luser32 -lgdi32 -lshlwapi -lkernel32 7 | CFLAGS:=-ffunction-sections -fdata-sections -DUSE_COMPAT 8 | LDFLAGS:= 9 | 10 | ifdef DEBUG 11 | CFLAGS+=-g -D_DEBUG 12 | else 13 | CFLAGS+=-O3 14 | endif 15 | 16 | ifneq (,$(findstring clang, $(CC))) 17 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 18 | LDFLAGS+=-Wl,/OPT:REF 19 | else 20 | CFLAGS+=-m32 21 | ifneq (,$(findstring gcc, $(CC))) 22 | LDFLAGS+= -Wl,--gc-sections\ 23 | -static-libgcc -static-libstdc++ \ 24 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 25 | -Wl,--no-whole-archive 26 | else 27 | LIBS+=kernel32.def 28 | endif 29 | endif 30 | 31 | all: aikimi_patch \ 32 | aikimi_loader_seh \ 33 | aikimi_chs 34 | 35 | aikimi_patch: $(SRC_DIR)/aikimi_patch.c 36 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 37 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 38 | rm -rf $(BUILD_DIR)/$@.exp 39 | rm -rf $(BUILD_DIR)/$@.lib 40 | 41 | # this may be seemed as virus 42 | aikimi_loader_seh: $(SRC_DIR)/aikimi_loader_seh.c 43 | $(CC) $^ -o $(BUILD_DIR)/$@.exe \ 44 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 45 | 46 | aikimi_chs: $(SRC_DIR)/aikimi_loader.c 47 | $(CC) $^ -o $(BUILD_DIR)/$@.exe -ldetours_v4010 \ 48 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 49 | 50 | .PHONY: aikimi_patch aikimi_chs aikimi_loader_seh -------------------------------------------------------------------------------- /project/livemaker/src/aikimi_loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef USE_COMPAT 4 | #include "detours_v4010.h" 5 | #else 6 | #include "detours.h" 7 | #endif 8 | 9 | #ifndef _DEBUG 10 | #pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup") 11 | #endif 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | //test(); 16 | STARTUPINFOA si = {0}; 17 | PROCESS_INFORMATION pi = {0}; 18 | si.cb = sizeof(STARTUPINFOA); 19 | ZeroMemory(&pi, sizeof(pi)); 20 | ZeroMemory(&si, sizeof(si)); 21 | 22 | // CreateProcessA( 23 | // "aikimi.exe", NULL, NULL, NULL, 24 | // FALSE, 0, NULL, NULL, &si, &pi); 25 | 26 | if(!DetourCreateProcessWithDllA( 27 | "aikimi.exe", NULL, NULL, NULL, 28 | FALSE, 0, NULL, NULL, &si, &pi, 29 | "aikimi_patch.dll", NULL)) 30 | { 31 | MessageBoxA(NULL, "start aikimi.exe failed!", "start error", 0); 32 | return -1; 33 | } 34 | WaitForSingleObject(pi.hProcess, INFINITE); 35 | CloseHandle(pi.hThread); 36 | CloseHandle(pi.hProcess); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /project/livemaker/src/compat/detours_v4010.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuriSizuku/GalgameReverse/e9e309986dd51ed65fc7c26c87de1d5f516cbc89/project/livemaker/src/compat/detours_v4010.lib -------------------------------------------------------------------------------- /project/livemaker/src/kernel32.def: -------------------------------------------------------------------------------- 1 | LIBRARY kernel32.dll 2 | 3 | EXPORTS 4 | AddVectoredExceptionHandler 5 | RemoveVectoredExceptionHandler -------------------------------------------------------------------------------- /project/majiro/majiro.mk: -------------------------------------------------------------------------------- 1 | CC:=clang 2 | BUILD_DIR:=asset/build 3 | INCS:=-Isrc/compat 4 | LIBS:=-luser32 -lgdi32 -lshlwapi -ladvapi32 -lpsapi 5 | CFLAGS:=-ffunction-sections -fdata-sections 6 | LDFLAGS:= 7 | 8 | ifdef DEBUG 9 | CFLAGS+=-g -D_DEBUG 10 | else 11 | CFLAGS+=-Os 12 | endif 13 | 14 | ifneq (,$(findstring clang, $(CC))) # for llvm-mingw 15 | CFLAGS+=-m32 -gcodeview -Wl,--pdb=$(BUILD_DIR)/majiro_patch.pdb 16 | LDFLAGS+= -Wl,--gc-sections 17 | else ifneq (,$(findstring gcc, $(CC))) # for mingw-w64 18 | CFLAGS+=-m32 19 | LDFLAGS+= -Wl,--gc-sections \ 20 | -static-libgcc -static-libstdc++ \ 21 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 22 | -Wl,--no-whole-archive 23 | else ifneq (,$(findstring tcc, $(CC))) # for tcc 24 | CFLAGS+=-m32 25 | else # for previous llvm clang with msvc 26 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 27 | LDFLAGS+=-Wl,/OPT:REF # for llvm 28 | endif 29 | 30 | all: prepare majiro_patch 31 | 32 | prepare: 33 | @mkdir -p $(BUILD_DIR) 34 | 35 | majiro_patch: src/majiro_patch.c 36 | @echo "## $@" 37 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 38 | -D USECOMPAT \ 39 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 40 | @rm -rf $(BUILD_DIR)/$@.exp 41 | @rm -rf $(BUILD_DIR)/$@.lib 42 | @rm -rf $(BUILD_DIR)/$@.def 43 | 44 | .PHONY: all prepare majiro_patch -------------------------------------------------------------------------------- /project/majiro/src/majiro_mjo.py: -------------------------------------------------------------------------------- 1 | """ 2 | majiro engine, decrypt mjo file, MajiroObjX1.000 -> MajiroObjV1.000 3 | v0.1, developed by devseed 4 | 5 | tested game: 6 | そらいろ (ねこねこソフト) v1.1 7 | ルリのかさね ~いもうと物語り (ねこねこソフト) 8 | 9 | See also, 10 | https://github.com/AtomCrafty/MajiroTools/wiki/Format%3A-Mjo-script 11 | https://github.com/AtomCrafty/MajiroTools/wiki/Method:-XOR-cipher 12 | 13 | """ 14 | 15 | import sys 16 | import struct 17 | from typing import List 18 | 19 | # util functions 20 | class struct_t(struct.Struct): 21 | """ 22 | base class for pack or unpack struct, 23 | _ for meta info, __ for internal info 24 | """ 25 | 26 | def __init__(self, data=None, cur=0, *, fmt=None, names=None) -> None: 27 | """" 28 | _meta_fmt: struct format 29 | _meta_names: method names 30 | """ 31 | 32 | if not hasattr(self, "_meta_names"): self._meta_names = [] 33 | if not hasattr(self, "_meta_fmt"): self._meta_fmt = "" 34 | if names: self._meta_names = names 35 | if fmt: self._meta_fmt = fmt 36 | super().__init__(self._meta_fmt) 37 | if data: self.frombytes(data, cur) 38 | 39 | def cppinherit(self, fmt, names): 40 | if not hasattr(self, "_meta_names"): self._meta_names = names 41 | else: self._meta_names = names + self._meta_names 42 | if not hasattr(self, "_meta_fmt"): self._meta_fmt = fmt 43 | else: self._meta_fmt += fmt.lstrip('<').lstrip('>') 44 | 45 | def frombytes(self, data, cur=0, *, fmt=None) -> None: 46 | if fmt: vals = struct.unpack_from(fmt, data, cur) 47 | else: vals = self.unpack_from(data, cur) 48 | names = self._meta_names 49 | for i, val in enumerate(vals): 50 | if i >= len(names): break 51 | setattr(self, names[i], val) 52 | self._data = data 53 | 54 | def tobytes(self, *, fmt=None) -> bytes: 55 | vals = [] 56 | names = self._meta_names 57 | for name in names: 58 | vals.append(getattr(self, name)) 59 | if fmt: _data = struct.pack(fmt, *vals) 60 | else: _data = self.pack(*vals) 61 | return _data 62 | 63 | # majiro functions 64 | class mjoheader_t(struct_t): 65 | def __init__(self, data=None, cur=0) -> None: 66 | self.magic = b'MajiroObjV1.000\0' 67 | self.main_offset, self.line_count, self.func_count = [0] * 3 68 | super().__init__(data, cur, fmt='<16s3I', 69 | names=['magic', 'main_offset', 'line_count', 'func_count']) 70 | 71 | class mjofunc_t(struct_t): 72 | def __init__(self, data=None, cur=0, *, fmt=None, names=None) -> None: 73 | self.hash, self.offset = [0]*2 74 | super().__init__(data, cur, fmt="<2I", names=['hash', 'offset']) 75 | 76 | class Mjo: 77 | @classmethod 78 | def crc32table(cls, idx): 79 | """ 80 | :param index: 0~255 81 | """ 82 | 83 | POLY = 0xEDB88320 84 | v = idx & 0xffffffff 85 | for _ in range(0, 8): 86 | if v & 0x1 != 0: v = (v >> 1) ^ POLY 87 | else: v >>= 1 88 | return v 89 | 90 | def __init__(self, data=None) -> None: 91 | self.m_header = mjoheader_t() 92 | self.m_funcs: List[mjofunc_t] = [] 93 | self.m_names: List[str] = [] 94 | self.m_codesize, self.m_codeoffset = [0]*2 95 | if data: self.parse(data) 96 | 97 | def parse(self, data: bytes): 98 | self.m_data = data 99 | self.m_header = mjoheader_t(data) 100 | cur = self.m_header.size 101 | for _ in range(self.m_header.func_count): 102 | func = mjofunc_t(data, cur) 103 | self.m_funcs.append(func) 104 | cur += func.size 105 | self.m_codesize, = struct.unpack_from("> j*8) & 0xff 118 | 119 | offset = self.m_codeoffset 120 | for i in range(self.m_codesize): 121 | self.m_data[offset+i] ^= XOR_TABLE[(keyoffset + i) % len(XOR_TABLE)] 122 | self.m_header.magic = self.m_header.magic.replace(b'X', b'V') 123 | self.m_data[:self.m_header.size] = self.m_header.tobytes() 124 | 125 | def decrypt_mjo(inpath, outpath="out.mjo"): 126 | with open(inpath, 'rb') as fp: 127 | data = bytearray(fp.read()) 128 | mjo = Mjo(data) 129 | mjo.decrypt() 130 | if outpath is not None: 131 | with open(outpath, 'wb') as fp: 132 | fp.write(mjo.m_data) 133 | return mjo.m_data 134 | 135 | def debug(): 136 | decrypt_mjo("build/workflow/2.pre/data_mjo/現代花子共通.mjo") 137 | 138 | def main(): 139 | if len(sys.argv) < 3: 140 | print("majiro_mjo d inpath [outpath]") 141 | return 142 | if sys.argv[1].lower() == 'd': 143 | outpath = sys.argv[3] if len(sys.argv) > 3 else "out.mjo" 144 | decrypt_mjo(sys.argv[2], outpath) 145 | else: raise ValueError(f"unknow format {sys.argv[1]}") 146 | 147 | if __name__ == '__main__': 148 | # debug() 149 | main() 150 | pass -------------------------------------------------------------------------------- /project/majiro/task/task_sorairo/Makefile: -------------------------------------------------------------------------------- 1 | # required variables: 2 | # WORK_DIR, build workflow dir 3 | # SRC_DIR, project src dir, usually ../../src 4 | # TOOL_DIR, external tool dir, usually ../../tool 5 | 6 | # optional variables 7 | # BASE_DIR, project basedir 8 | # GAME_EXEC, use which command to launch game 9 | # GAME_FILE, origin game package path 10 | # GAME_DIR, game dir for testing 11 | 12 | # usage: 13 | # in linux, "source ./_env.sh" 14 | # in windows, "msys2_shell -here -no-start -defterm -full-path" to activate, then "source ./_env.sh" 15 | 16 | # _env.sh example 17 | # export GAME_NAME=Sorairo 18 | # export GAME_ID=vndb-v1914 19 | # if [ -n "$(uname -a | grep Msys)" ]; then 20 | # export BASE_DIR=/d/Downloads/$GAME_NAME 21 | # export GAME_EXEC=start 22 | # else 23 | # LOCPATH=~/.wine/locale 24 | # if ! [ -d $LOCPATH/zh_CN.UTF-8 ]; then 25 | # mkdir -p $LOCPATH 26 | # localedef -f UTF-8 -i zh_CN $LOCPATH/zh_CN.UTF-8 27 | # fi 28 | # export BASE_DIR=~/Downloads/$GAME_NAME 29 | # export GAME_EXEC=LOCPATH=$LOCPATH\ LANG=zh_CN.UTF-8\ wine 30 | # fi 31 | # export GAME_FILE=$BASE_DIR/${GAME_ID}.7z 32 | # export GAME_DIR=$BASE_DIR/${GAME_ID}_rebuild 33 | # export WORK_DIR=$BASE_DIR/workflow 34 | # export SRC_DIR=../../src 35 | # export TOOL_DIR=../../tool 36 | 37 | all: 38 | @echo build Sorairo chspatch 39 | @make build_1mjo 40 | @make build_2arc 41 | @make build_3dll 42 | @make build_3exe 43 | 44 | link: 45 | @if ! [ -d workflow ]; then \ 46 | ln -s $(WORKFLOW_DIR) workflow;\ 47 | fi 48 | 49 | unlink: 50 | @rm -rf workflow 51 | 52 | init_mingwsdk init_workdir init_gamedir: 53 | @./init.sh $@ 54 | 55 | build_1mjo build_2arc build_3dll build_3exe: init_workdir 56 | @./build.sh $@ 57 | 58 | release_patch: 59 | @./build.sh $@ 60 | 61 | run: 62 | @cd $(GAME_DIR);$(GAME_EXEC) sorairo_chs.exe 63 | 64 | # vscode launch.json config 65 | # can not pause while running, can only set breakpoint on pause or before launch 66 | # "name": "linux sorairo", 67 | # "type": "cppdbg", 68 | # "request": "launch", 69 | # "program": "sorairo_chs.exe", 70 | # "args": [], 71 | # "cwd": "~/Downloads/Sorairo/vndb-v1914_rebuild/", 72 | # "stopAtEntry": false, 73 | # "environment": [], 74 | # "MIMode": "gdb", 75 | # "miDebuggerPath": "/usr/bin/i686-w64-mingw32-gdb", 76 | # "miDebuggerServerAddress": "localhost:1234", 77 | run_gdbserver: 78 | @cd $(GAME_DIR); LOCPATH=~/.wine/locale LANG=zh_CN.UTF-8 \ 79 | wine Z:/usr/share/win32/gdbserver.exe localhost:1234 sorairo_chs.exe 80 | 81 | send: init_gamedir 82 | @cp -rf $(WORK_DIR)/5.result/* $(GAME_DIR) 83 | 84 | test: 85 | @make send 86 | @make run 87 | 88 | clean: 89 | @rm -f $(WORK_DIR)/*.7z 90 | @rm -rf ${WORK_DIR}/5.result 91 | 92 | .PHONY: all link unlink \ 93 | init_workdir init_gamedir \ 94 | build_1mjo build_2arc build_3dll build_3exe \ 95 | release_patch run send test clean -------------------------------------------------------------------------------- /project/majiro/task/task_sorairo/build.sh: -------------------------------------------------------------------------------- 1 | build_1mjo() { 2 | echo "## build_1mjo" 3 | 4 | echo "## ftext -> mjil" 5 | for inpath in $(ls ${WORK_DIR}/3.edit/data_ftext/*.txt); do 6 | inname=$(basename $inpath ".mjil.txt") # xxx.mjil 7 | echo $inname.mjil.txt 8 | python -B ${SRC_DIR}/majiro_mjiltext.py icp936 $inpath \ 9 | ${WORK_DIR}/2.pre/data_mjil/$inname.mjil \ 10 | ${WORK_DIR}/4.post/data_mjil/$inname.mjil 11 | done 12 | 13 | echo "## mjil adjust" 14 | if [ -f ${WORK_DIR}/3.edit/sorairo_adjust.py ]; then 15 | python -B ${WORK_DIR}/3.edit/sorairo_adjust.py ${WORK_DIR}/4.post/data_mjil 16 | fi 17 | 18 | echo "## mjil -> mjo, from data_ftext" 19 | for inpath in $(ls ${WORK_DIR}/3.edit/data_ftext/*.txt); do 20 | inname=$(basename $inpath ".mjil.txt") # xxx.mjil 21 | echo $inname.mjil 22 | cd ${TOOL_DIR} 23 | python -B -m mjotool2 -G sorairo \ 24 | -a ${WORK_DIR}/4.post/data_mjil/$inname.mjil \ 25 | ${WORK_DIR}/4.post/data_mjov/$inname.mjo \ 26 | --text-encoding cp936 27 | cd - 28 | done 29 | 30 | echo "## mjil-> mjo from data_mjil" 31 | for inpath in $(ls ${WORK_DIR}/3.edit/data_mjil/*.mjil); do 32 | inname=$(basename $inpath ".mjil") # xxx.mjil 33 | echo $inname.mjil 34 | cd ${TOOL_DIR} 35 | python -B -m mjotool2 -G sorairo \ 36 | -a ${WORK_DIR}/3.edit/data_mjil/$inname.mjil \ 37 | ${WORK_DIR}/4.post/data_mjov/$inname.mjo \ 38 | --text-encoding cp936 39 | cd - 40 | done 41 | } 42 | 43 | build_2arc() { 44 | echo "## build_2arc" 45 | cp -f ${WORK_DIR}/4.post/data_mjov/*.mjo ${WORK_DIR}/4.post/update/ 46 | cp -f ${WORK_DIR}/3.edit/data_cfg/* ${WORK_DIR}/4.post/update/ 47 | cp -f ${WORK_DIR}/3.edit/data_png/*.png ${WORK_DIR}/4.post/update/ 48 | cp -f ${WORK_DIR}/1.origin/update2.arc ${WORK_DIR}/5.result/update5.arc 49 | python ${SRC_DIR}/majiro_arc.py b \ 50 | ${WORK_DIR}/4.post/update \ 51 | ${WORK_DIR}/5.result/override/update5.arc 52 | } 53 | 54 | build_3dll() { 55 | echo "## build_3dll" 56 | if [ -z "$CC" ]; then 57 | if [ -z "$(uname -a | grep Linux)" ]; then 58 | CC=clang 59 | else 60 | CC=i686-w64-mingw32-gcc 61 | fi 62 | fi 63 | make -C ${SRC_DIR}/../ -f majiro.mk CC=$CC BUILD_DIR=${WORK_DIR}/5.result DEBUG=1 64 | } 65 | 66 | build_3exe() { 67 | echo "## build_3exe" 68 | cp -f ${WORK_DIR}/1.origin/そらいろ_v1.1.exe ${WORK_DIR}/4.post/_sorairo_chs.exe 69 | 70 | if [ -f ${WORK_DIR}/3.edit/sorairo_sjis.txt ]; then 71 | echo "## import sorairo_sjis.txt" 72 | python -B ${SRC_DIR}/compat/libtext_v610.py insert \ 73 | ${WORK_DIR}/4.post/_sorairo_chs.exe \ 74 | ${WORK_DIR}/3.edit/sorairo_sjis.txt \ 75 | -o ${WORK_DIR}/4.post/_sorairo_chs.exe \ 76 | -e "gbk" --bytes_padding 00 --text_replace 〜 ~ \ 77 | --log_level error 78 | fi 79 | 80 | if [ -f ${WORK_DIR}/3.edit/sorairo_utf16.txt ]; then 81 | echo "## import sorairo_utf16.txt" 82 | python -B ${SRC_DIR}/compat/libtext_v610.py insert \ 83 | ${WORK_DIR}/4.post/_sorairo_chs.exe \ 84 | ${WORK_DIR}/3.edit/sorairo_utf16.txt \ 85 | -o ${WORK_DIR}/4.post/_sorairo_chs.exe \ 86 | -e "utf-16le" --bytes_padding 2000 \ 87 | --log_level error 88 | fi 89 | 90 | echo "## inject majiro_patch.dll to sorairo" 91 | python -B ${SRC_DIR}/compat/windllin_v321.py -m codecave2 \ 92 | ${WORK_DIR}/4.post/_sorairo_chs.exe majiro_patch.dll \ 93 | -o ${WORK_DIR}/5.result/sorairo_chs.exe 1>/dev/null 94 | 95 | echo "## generate config file" 96 | echo "charset=134" > ${WORK_DIR}/5.result/override/config.ini 97 | echo "codepage=936" >> ${WORK_DIR}/5.result/override/config.ini 98 | echo "patch=+38C0:C3;+1903B:B8A1;+19087:B8A1;+19A7A:B8A1;+1905D:B9A1;+19AF0:B9A1" >> ${WORK_DIR}/5.result/override/config.ini 99 | } 100 | 101 | release_patch() { 102 | echo "## release_patch"W 103 | RELEASE_NAME="[$(date +"%y%m%d")build][vndb-v1914]Sorairo_${VERSION}[1CHSPATCH]" 104 | RELEASE_FILE=${WORK_DIR}/$RELEASE_NAME.7z 105 | RELEASE_DIR=${WORK_DIR}/5.result 106 | echo $RELEASE_NAME 107 | 7z a -mx5 $RELEASE_FILE $RELEASE_DIR 108 | 7z rn $RELEASE_FILE $(basename $RELEASE_DIR) $RELEASE_NAME 109 | } 110 | 111 | $* -------------------------------------------------------------------------------- /project/majiro/task/task_sorairo/init.sh: -------------------------------------------------------------------------------- 1 | extract_mjox() { 2 | indir=$1 3 | outdir=$2 4 | echo "## extract_mjox $indir -> $outdir" 5 | if [ -z "$outdir" ]; then outdir=$indir; fi 6 | for file in $(ls ${indir}/*.mjo); do 7 | inname=$(basename $file) 8 | echo $inname 9 | python -B ${SRC_DIR}/majiro_mjo.py d $file $outdir/$inname 10 | done 11 | } 12 | 13 | extract_mjil() { 14 | indir=$1 15 | outdir=$2 16 | echo "## extract_mjotext $indir -> $outdir" 17 | 18 | # mjo -> mjil 19 | cd $TOOL_DIR 20 | for file in $(ls ${indir}/*.mjo); do 21 | inname=$(basename $file) 22 | echo $inname 23 | python -B -m mjotool2 -G sorairo -d $file $outdir/${inname%.*}.mjil 24 | done 25 | cd - 26 | } 27 | 28 | extract_mjiltext() { 29 | indir=$1 30 | outdir=$2 31 | echo "## extract_mjotext $indir -> $outdir" 32 | 33 | # mjil -> ftext 34 | for file in $(ls ${indir}/*.mjil); do 35 | inname=$(basename $file) 36 | echo $inname 37 | python -B ${SRC_DIR}/majiro_mjiltext.py e $file $outdir/${inname}.txt 38 | done 39 | } 40 | 41 | init_mingwsdk() { 42 | echo "## init_mingwsdk ${MINGWSDK}" 43 | if ! [ -d ${MINGWSDK} ]; then 44 | if [ -n "$(uname -a | grep Linux)" ]; then 45 | curl -fsSL https://github.com/mstorsjo/llvm-mingw/releases/download/20240619/llvm-mingw-20240619-msvcrt-ubuntu-20.04-x86_64.tar.xz -o /tmp/llvm-mingw.tar.xz 46 | tar xf /tmp/llvm-mingw.tar.xz -C /tmp 47 | _tmppath=/tmp/llvm-mingw-20240619-msvcrt-ubuntu-20.04-x86_64 48 | mv -f ${_tmppath} $MINGWSDK || echo "try to use sudo mv to $MINGWSDK" && sudo mv -f ${_tmppath} $MINGWSDK 49 | rm -rf /tmp/llvm-mingw.tar.xz 50 | else 51 | curl -fsSL https://github.com/mstorsjo/llvm-mingw/releases/download/20240619/llvm-mingw-20240619-msvcrt-x86_64.zip -o ~/llvm-mingw.zip 52 | 7z x ~/llvm-mingw.zip -o$HOME 53 | mv -f ~/llvm-mingw-20240619-msvcrt-x86_64 $MINGWSDK 54 | rm -rf ~/llvm-mingw.zip 55 | fi 56 | fi 57 | } 58 | 59 | init_gamedir() { 60 | if ! [ -d ${GAME_DIR} ]; then 61 | echo "## init_gamedir ${GAME_DIR} <- ${GAME_FILE}" 62 | mkdir -p ${GAME_DIR} 63 | 7z x $GAME_FILE -o${GAME_DIR} 64 | if [ "$(ls ${GAME_DIR} | wc -w)" -le 1 ]; then 65 | _path=${GAME_DIR}/$(ls ${GAME_DIR}) 66 | for file in $(ls $_path); do 67 | mv -f $_path/$file ${GAME_DIR} 68 | done 69 | fi 70 | fi 71 | } 72 | 73 | init_workdir() { 74 | if ! [ -d ${WORK_DIR}/1.origin ]; then 75 | echo "## init_workdir 1.origin" 76 | mkdir -p ${WORK_DIR}/1.origin 77 | 7z e ${GAME_FILE%} */*.exe -o${WORK_DIR}/1.origin 78 | 7z e ${GAME_FILE%} */scenario.arc -o${WORK_DIR}/1.origin 79 | 7z e ${GAME_FILE%} */update*.arc -o${WORK_DIR}/1.origin 80 | fi 81 | 82 | if ! [ -d ${WORK_DIR}/2.pre ]; then 83 | echo "## init_workdir 2.pre" 84 | mkdir -p ${WORK_DIR}/2.pre 85 | mkdir -p ${WORK_DIR}/2.pre/data_cfg 86 | mkdir -p ${WORK_DIR}/2.pre/data_mjox 87 | mkdir -p ${WORK_DIR}/2.pre/data_mjov 88 | mkdir -p ${WORK_DIR}/2.pre/data_mjil 89 | 90 | # extract arc 91 | python -B ${SRC_DIR}/majiro_arc.py e ${WORK_DIR}/1.origin/scenario.arc ${WORK_DIR}/2.pre/data_mjox 1>/dev/null 92 | for file in $(ls -rt ${WORK_DIR}/1.origin/update*.arc); do 93 | echo $(basename $file) 94 | python ${SRC_DIR}/majiro_arc.py e $file ${WORK_DIR}/2.pre/data_mjox 1>/dev/null 95 | done 96 | mv -f ${WORK_DIR}/2.pre/data_mjox/*.cfg ${WORK_DIR}/2.edit/data_cfg/ 97 | mv -f ${WORK_DIR}/2.pre/data_mjox/*.env ${WORK_DIR}/2.edit/data_cfg/ 98 | 99 | # extract mjo 100 | extract_mjox ${WORK_DIR}/2.pre/data_mjox ${WORK_DIR}/2.pre/data_mjov 101 | extract_mjil ${WORK_DIR}/2.pre/data_mjox ${WORK_DIR}/2.pre/data_mjil/ 102 | fi 103 | 104 | if ! [ -d ${WORK_DIR}/3.edit ]; then 105 | echo "## init_workdir 3.edit" 106 | mkdir -p ${WORK_DIR}/3.edit 107 | mkdir -p ${WORK_DIR}/3.edit/data_cfg 108 | mkdir -p ${WORK_DIR}/3.edit/data_mjil 109 | mkdir -p ${WORK_DIR}/3.edit/data_ftext 110 | mkdir -p ${WORK_DIR}/3.edit/data_png 111 | extract_mjiltext ${WORK_DIR}/2.pre/data_mjil/ ${WORK_DIR}/3.edit/data_ftext 112 | fi 113 | 114 | if ! [ -d ${WORK_DIR}/4.post ]; then 115 | echo "## init_workdir 4.post" 116 | mkdir -p ${WORK_DIR}/4.post 117 | mkdir -p ${WORK_DIR}/4.post/data_mjil 118 | mkdir -p ${WORK_DIR}/4.post/data_mjov 119 | mkdir -p ${WORK_DIR}/4.post/update 120 | fi 121 | 122 | if ! [ -d ${WORK_DIR}/5.result ]; then 123 | echo "## init_workdir 5.result" 124 | mkdir -p ${WORK_DIR}/5.result 125 | mkdir -p ${WORK_DIR}/5.result/override 126 | mkdir -p ${WORK_DIR}/5.result/override/savedata 127 | fi 128 | } 129 | 130 | $* # to call function outside script -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/README.md: -------------------------------------------------------------------------------- 1 | # mjotool2 2 | 3 | A python module program for disassembling Majiro `.mjo` scripts, and outputting analyzed instruction blocks. Multi encoding asm support by devseed. You can use `--text-encoding` option for default text and `[[cp936]]` at the start of the string in seperate. 4 | 5 | Default behavior is to print an input script to the console, **which is VERY VERBOSE**. 6 | 7 | ## Usage 8 | 9 | ``` 10 | usage: python -m mjotool [-h] [-p MJO] [-d MJO MJILE] [-a MJILE MJO] 11 | [-G NAME] [-H FLGS] [-A FLGS] [-C] [-R] 12 | 13 | Majiro script IL disassembler and assembler tool 14 | 15 | optional arguments: 16 | -h, --help show this help message and exit 17 | -p, --print MJO print mjo script file/directory to the console 18 | -d, --disasm MJO MJIL disassemble mjo script file/directory to output file/directory 19 | -a, --asm MJIL MJO assemble mjil script file/directory to output file/directory 20 | -G, --group NAME group name directive disassembler option 21 | -H, --hash FLGS unhashing disassembler options 22 | -A, --alias FLGS alias naming disassembler options 23 | -C, --no-color disable color printing 24 | --text_encoding asm text encoding default cp932 25 | 26 | internal arguments: 27 | -R, --research run custom research functions that are not intended 28 | for use 29 | 30 | Disassembler Options: 31 | [-G|--group] group directive 32 | -------------------------------------------- 33 | "NAME" : strip group name from hash names that contain provided group 34 | 35 | on|off [-H|--hash] hashing options 36 | -------------------------------------------- 37 | >k| K : known_hashes (enable all functionality below) 38 | >a| A : annotations (';' comments for known hashes or hash values) 39 | >i| I : inline_hash (inline hash function $name for known names) 40 | e|>E : explicit_inline_hash (explicit inline hash function ${name}) 41 | >s| S : syscall_inline_hash (inline hashing for syscalls - which work by lookup) 42 | >l| L : int_inline_hash (inline hashing for matching int literals) 43 | >g| G : implicit_local_groups (strip empty @ group names from locals) 44 | 45 | on|off [-A|--alias] aliasing/shorthand options 46 | -------------------------------------------- 47 | v|>V : explicit_varoffset (remove -1 var offset for non-locals) 48 | m|>M : modifier_aliases (modifier flags: inc.x, dec.x, x.inc, x.dec) 49 | s|>S : scope_aliases (scope flags: persist, save, -, loc) 50 | t|>T : vartype_aliases (var type flags: i, r, s, iarr, rarr, sarr) 51 | l|>L : typelist_aliases (type list: i, r, s, iarr, rarr, sarr) 52 | f|>F : functype_aliases (func arg types: i, r, s, iarr, rarr, sarr) 53 | d|>D : explicit_dim0 (always include dimension flag: dim0) 54 | ``` 55 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """Majiro script tools library 4 | """ 5 | 6 | __version__ = '0.1.1' 7 | __date__ = '2023-08-12' 8 | __author__ = 'Robert Jordan, devseed' 9 | __credits__ = '''Original C# implementation by AtomCrafty - 2021 10 | Converted to Python library by Robert Jordan - 2021 11 | ''' 12 | 13 | ####################################################################################### 14 | 15 | from .opcodes import Opcode 16 | from .script import Instruction, MjoScript 17 | from .analysis import ControlFlowGraph 18 | 19 | from . import crypt 20 | from . import flags 21 | from . import opcodes 22 | from . import script 23 | from . import analysis 24 | 25 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/_research.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """Majiro script research 4 | 5 | Personal script used in __main__ for programmatically searching mjo scripts for 6 | instructions of interest. This script changes often, so it may be excluded from commits. 7 | 8 | __main__ will run fine, even if this module is missing 9 | """ 10 | 11 | __version__ = '0.0.1' 12 | __date__ = '2021-04-09' 13 | __author__ = 'Robert Jordan' 14 | 15 | ####################################################################################### 16 | 17 | import argparse, os, struct 18 | from ._util import DummyColors, Colors 19 | from .script import Instruction, MjoScript, Function, ILFormat 20 | from .analysis import ControlFlowGraph 21 | 22 | 23 | ## RESEARCH HANDLING ## 24 | 25 | def _init_parser(parser:argparse.ArgumentParser): 26 | """Add any extra arguments to the parser 27 | """ 28 | pass 29 | 30 | def _init_args(args): 31 | """Do any initial setup after parser.parse_args() is run 32 | """ 33 | pass 34 | 35 | # do whatever we need to with any input files 36 | def do_research(args, filename:str, *, options:ILFormat=ILFormat.DEFAULT): 37 | """Do whatever we need to with input script files 38 | """ 39 | #script:MjoScript = read_script(filename) 40 | #cfg:ControlFlowGraph = analyze_script(script) 41 | pass 42 | 43 | 44 | ## READ / ANALYZE SCRIPT ## 45 | 46 | def read_script(filename:str) -> MjoScript: 47 | """Read and return a MjoScript from file 48 | """ 49 | with open(filename, 'rb') as f: 50 | return MjoScript.disassemble_script(f) 51 | 52 | def analyze_script(script:MjoScript) -> ControlFlowGraph: 53 | """Return the analysis of a script's control flow, blocks, functions, etc. 54 | 55 | argument can also be a filename 56 | """ 57 | if isinstance(script, str): # is argument filename? 58 | script = read_script(script) 59 | return ControlFlowGraph.build_from_script(script) 60 | 61 | 62 | ####################################################################################### 63 | 64 | ## RESEARCH FUNCTIONS ## 65 | 66 | #... 67 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/known_hashes/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """Known syscall, usercall, and variable hashes, and callbacks and group names. 4 | """ 5 | 6 | __version__ = '1.0.0' 7 | __date__ = '2021-05-04' 8 | __author__ = 'Robert Jordan' 9 | 10 | __all__ = ['LOCAL_VARS', 'LOCAL_VARS_LOOKUP', 'THREAD_VARS', 'THREAD_VARS_LOOKUP', 'SAVEFILE_VARS', 'SAVEFILE_VARS_LOOKUP', 'PERSISTENT_VARS', 'PERSISTENT_VARS_LOOKUP', 'FUNCTIONS', 'FUNCTIONS_LOOKUP', 'SYSCALLS', 'SYSCALLS_LOOKUP', 'GROUPS', 'GROUPS_LOOKUP', 'CALLBACKS', 'CALLBACKS_LOOKUP', 'SYSCALLS_LIST', 'VARIABLES', 'VARIABLES_LOOKUP'] 11 | 12 | ####################################################################################### 13 | 14 | ## runtime imports: 15 | # from ..crypt import hash32 # used in find_group() 16 | 17 | from itertools import chain 18 | from typing import Dict, Optional 19 | 20 | from ._hashes import * 21 | 22 | 23 | # combine all variable type hashes into one dictionary for easy lookup, 24 | # since this isn't handled by the auto-generated file 25 | VARIABLES:Dict[int,str] = dict(chain(LOCAL_VARS.items(), THREAD_VARS.items(), SAVEFILE_VARS.items(), PERSISTENT_VARS.items())) 26 | VARIABLES_LOOKUP:Dict[str,int] = dict((v,k) for k,v in VARIABLES.items()) 27 | 28 | # function name used calculate hashes in GROUPS lookup dictionary 29 | GROUP_HASHNAME:str = '$main' 30 | 31 | def find_group(hashvalue:int, name:str=GROUP_HASHNAME) -> Optional[str]: 32 | """find_group(0x1d128f30, '$main') -> 'GLOBAL' 33 | 34 | search for a group name that matches the hash value when combined into `name@GROUP`. 35 | """ 36 | if name is GROUP_HASHNAME: # this is built into _hashes.GROUPS dict 37 | return GROUPS.get(hashvalue, None) 38 | 39 | from ..crypt import hash32 40 | init = hash32(f'{name}@') 41 | for group in GROUPS: 42 | if hash32(group, init) == hashvalue: 43 | return group 44 | return None 45 | 46 | 47 | del chain, Dict, Optional # cleanup declaration-only imports 48 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/mjs/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """ 4 | """ 5 | 6 | __version__ = '0.1.0' 7 | __date__ = '2021-05-04' 8 | __author__ = 'Robert Jordan' 9 | 10 | ####################################################################################### 11 | 12 | from .identifiers import * 13 | from .mjsreader import MjsReader 14 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/sheets/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """Helper class for programmatically downloading/exporting Google Sheets 4 | 5 | 6 | """ 7 | 8 | __version__ = '1.0.0' 9 | __date__ = '2021-05-03' 10 | __author__ = 'Robert Jordan' 11 | 12 | __all__ = [] 13 | 14 | ####################################################################################### 15 | 16 | from .googlesheets import GoogleSheet 17 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/sheets/googlesheets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """Helper class for programmatically downloading/exporting Google Sheets 4 | 5 | 6 | """ 7 | 8 | __version__ = '1.0.0' 9 | __date__ = '2021-04-29' 10 | __author__ = 'Robert Jordan' 11 | 12 | __all__ = ['GoogleSheet'] 13 | 14 | ####################################################################################### 15 | 16 | ## runtime imports: 17 | # import urllib.request # used in GoogleSheet.download(...) 18 | 19 | import io 20 | from collections import namedtuple 21 | from typing import Optional 22 | 23 | 24 | #region ## GOOGLE SHEET DOWNLOAD ## 25 | 26 | class GoogleSheet(namedtuple('GoogleSheet', ('longid', 'gid'))): 27 | def __new__(cls, longid:str, gid:Optional[int]=None): 28 | return super().__new__(cls, longid, gid) 29 | 30 | def with_gid(self, gid:int) -> 'GoogleSheet': 31 | """gsheet.with_gid(gid) -> GoogleSheet(gsheet.longid, gid) 32 | """ 33 | return GoogleSheet(self.longid, gid) 34 | 35 | @property 36 | def url(self) -> str: 37 | """gsheet.url -> csv_download_url:str 38 | 39 | alias for: gsheet.geturl() 40 | """ 41 | return self.geturl() 42 | def geturl(self, gid:int=..., *, format:str='csv') -> str: 43 | """gsheet.get_url() -> csv_download_url:str 44 | gsheet.get_url([gid], format='tsv') -> tsv_download_url:str for new gid 45 | 46 | arguments: 47 | gid - override GID "sheet" ID. 48 | format - file format supported by Google Sheets (i.e. 'csv', 'tsv'). 49 | 50 | returns: 51 | str - download url for Google Sheet. 52 | """ 53 | #source: 54 | if gid is Ellipsis: 55 | gid = 0 if self.gid is None else self.gid 56 | elif gid is None: 57 | gid = 0 58 | return f'https://docs.google.com/spreadsheets/d/{self.longid}/export?gid={gid}&format={format}&id={self.longid}' 59 | 60 | def download(self, gid:int=..., *, format:str='csv', remove_crlf:bool=True, ignore_status:bool=False) -> str: 61 | """gsheet.download() -> csv_file:str 62 | gsheet.download([gid], format='tsv') -> tsv_file:str for new gid 63 | 64 | arguments: 65 | gid - override GID "sheet" ID. 66 | format - file format supported by Google Sheets (i.e. 'csv', 'tsv'). 67 | remove_crlf - replace all newlines '\\r\\n' (CRLF) with '\\n' (LF). 68 | ignore_status - do not raise exception for non-200 HTTP statuses. 69 | 70 | returns: 71 | str - text data of downloaded Google Sheet in specified format. 72 | """ 73 | url:str = self.geturl(gid, format=format) 74 | 75 | #source: 76 | import urllib.request # this import is sloooooooooooow 77 | response = urllib.request.urlopen(url) 78 | if not ignore_status and response.status != 200: 79 | raise Exception(f'Unexpected HTTP response status {response.status}') 80 | data:str = response.read().decode('utf-8') 81 | if remove_crlf: 82 | data = data.replace('\r\n', '\n') 83 | return data 84 | 85 | def open(self, gid:int=..., *, format:str='csv', remove_crlf:bool=True, ignore_status:bool=False) -> io.StringIO: 86 | """gsheet.open() -> io.StringIO(csv_file:str) 87 | gsheet.open([gid], format='tsv') -> io.StringIO(tsv_file:str for new gid) 88 | 89 | arguments: 90 | gid - override GID "sheet" ID. 91 | format - file format supported by Google Sheets (i.e. 'csv', 'tsv'). 92 | remove_crlf - replace all newlines '\\r\\n' (CRLF) with '\\n' (LF). 93 | ignore_status - do not raise exception for non-200 HTTP statuses. 94 | 95 | returns: 96 | io.StringIO - string reader of downloaded Google Sheet in specified format. 97 | """ 98 | return io.StringIO(self.download(gid, format=format, remove_crlf=remove_crlf, ignore_status=ignore_status)) 99 | 100 | #endregion 101 | 102 | 103 | del namedtuple, Optional # cleanup declaration-only imports 104 | -------------------------------------------------------------------------------- /project/majiro/tool/mjotool2/sheets/majirodata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | """ 4 | """ 5 | 6 | __version__ = '0.1.0' 7 | __date__ = '2021-05-03' 8 | __author__ = 'Robert Jordan' 9 | 10 | __all__ = ['MajiroData', 'MajiroData_Syscalls', 'MajiroData_Groups', 'MajiroData_Functions', 'MajiroData_Variables', 'MajiroData_Locals', 'MajiroData_Callbacks', 'MajiroData_Games', 'SheetSyscalls', 'SheetGroups', 'SheetFunctions', 'SheetVariables', 'SheetLocals', 'SheetCallbacks', 'SheetGames'] 11 | 12 | ####################################################################################### 13 | 14 | from .googlesheets import GoogleSheet 15 | from .rowtypes import RowSyscall, RowGroup, RowFunction, RowVariable, RowLocal, RowCallback, RowGame 16 | from .csvsheet import CsvSheet 17 | 18 | ####################################################################################### 19 | 20 | #region ## GOOGLE SHEET IDS ## 21 | 22 | MajiroData:GoogleSheet = GoogleSheet(r"1p03_q6VTfYQEjlDhpypgoPdLQREhXwXz2ObTUkz5dlY") 23 | ## Hash|Address|Return|Name|Arguments|Status|Notes 24 | MajiroData_Syscalls:GoogleSheet = MajiroData.with_gid(0) 25 | ## Hash|Source|Name|Status|Notes 26 | MajiroData_Groups:GoogleSheet = MajiroData.with_gid(1562764366) 27 | ## Hash|Source|Return|Name|Group|Arguments|Status|Notes 28 | MajiroData_Functions:GoogleSheet = MajiroData.with_gid(72122782) 29 | ## Hash|Source|Scope|Type|Name|Group|Status|Notes 30 | MajiroData_Variables:GoogleSheet = MajiroData.with_gid(380736744) 31 | ## Hash|Type|Name|Status|Notes 32 | MajiroData_Locals:GoogleSheet = MajiroData.with_gid(1596196937) 33 | ## Hash|Invoked by|Name|Status|Notes 34 | MajiroData_Callbacks:GoogleSheet = MajiroData.with_gid(750354284) 35 | ## Release|Developer|Name|Engine Build Date|Notes 36 | MajiroData_Games:GoogleSheet = MajiroData.with_gid(2017266804) 37 | 38 | #endregion 39 | 40 | class SheetSyscalls(CsvSheet, sheetname='Syscalls', sheetid=MajiroData_Syscalls, rowtype=RowSyscall): 41 | pass 42 | 43 | class SheetGroups(CsvSheet, sheetname='Groups', sheetid=MajiroData_Groups, rowtype=RowGroup): 44 | pass 45 | 46 | class SheetFunctions(CsvSheet, sheetname='Functions', sheetid=MajiroData_Functions, rowtype=RowFunction): 47 | pass 48 | 49 | class SheetVariables(CsvSheet, sheetname='Variables', sheetid=MajiroData_Variables, rowtype=RowVariable): 50 | pass 51 | 52 | class SheetLocals(CsvSheet, sheetname='Locals', sheetid=MajiroData_Locals, rowtype=RowLocal): 53 | pass 54 | 55 | class SheetCallbacks(CsvSheet, sheetname='Callbacks', sheetid=MajiroData_Callbacks, rowtype=RowCallback): 56 | pass 57 | 58 | class SheetGames(CsvSheet, sheetname='Games', sheetid=MajiroData_Games, rowtype=RowGame): 59 | pass 60 | 61 | -------------------------------------------------------------------------------- /project/majiro/winterpolaris.mk: -------------------------------------------------------------------------------- 1 | # use clang because of detours and naked asm 2 | CC:=clang 3 | BUILD_DIR:=asset/build 4 | INCS:=-Isrc/compat 5 | LIBDIRS:=-Lsrc/compat 6 | LIBS:=-luser32 -lgdi32 7 | CFLAGS:=-ffunction-sections -fdata-sections 8 | LDFLAGS:= 9 | 10 | ifdef DEBUG 11 | CFLAGS+=-g -D_DEBUG 12 | else 13 | CFLAGS+=-Os 14 | endif 15 | 16 | ifneq (,$(findstring clang, $(CC))) 17 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 18 | LDFLAGS+=-Wl,/OPT:REF 19 | else 20 | CFLAGS+=-m32 21 | ifneq (,$(findstring gcc, $(CC))) 22 | LDFLAGS+=-Wl,--gc-sections\ 23 | -static-libgcc -static-libstdc++ \ 24 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 25 | -Wl,--no-whole-archive\ 26 | -masm intel 27 | endif 28 | endif 29 | 30 | all: prepare winterpolaris_patch 31 | 32 | prepare: 33 | if ! [ -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR);fi 34 | 35 | clean: 36 | rm -rf $(BUILD_DIR)/* 37 | 38 | winterpolaris_patch: src/winterpolaris_patch.c 39 | $(CC) $^ -o $(BUILD_DIR)/$@.dll $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) -shared 40 | rm -rf $(BUILD_DIR)/$@.exp 41 | rm -rf $(BUILD_DIR)/$@.ilk 42 | rm -rf $(BUILD_DIR)/$@.lib 43 | 44 | .PHONY: prepare all clean winterpolaris_patch -------------------------------------------------------------------------------- /project/nippon1/src/ykcmp.py: -------------------------------------------------------------------------------- 1 | """ 2 | A python implementation for 3 | decompressing and compressing the ykcmp compress structure 4 | according to https://github.com/iltrof/ykcmp/wiki/Decompression 5 | developed by devseed, v0.1 6 | """ 7 | 8 | import struct 9 | from io import BytesIO 10 | 11 | class ykcmp_t(struct.Struct): 12 | def __init__(self, data=None): 13 | super().__init__('<8s3I') 14 | self.frombytes(data) 15 | 16 | def frombytes(self, data): 17 | if data==None: 18 | data = b'YKCMP_V1\x04\x00\x00\x00' + b'\x00'*8 19 | (self.magic, 20 | self.type, # 04 00 00 00 21 | self.ykcmpsize, 22 | self.rawsize) = self.unpack_from(data, 0) 23 | self.content = data[0x14:] 24 | 25 | def tobytes(self): 26 | data = bytearray(self.ykcmpsize + 0x14) 27 | self.pack_into(data, 0, 28 | self.magic, 29 | self.type, 30 | self.ykcmpsize, 31 | self.rawsize) 32 | data[0x14:] = self.content 33 | return data 34 | 35 | def decompress_ykcmpv1(data, outpath=""): 36 | ykcmp = ykcmp_t(data) 37 | if ykcmp.magic != b'YKCMP_V1': 38 | raise ValueError("unsupport format ", ykcmp.magic) 39 | 40 | resdata = bytearray(ykcmp.rawsize) 41 | orgpos = 0 42 | dstpos = 0 43 | while orgpos < len(ykcmp.content): 44 | c0 = ykcmp.content[orgpos] 45 | if c0 < 0x80: # forward copy XX 46 | offset = 1 47 | size = c0 48 | resdata[dstpos: dstpos+size] = \ 49 | ykcmp.content[orgpos+offset: orgpos+offset+size] 50 | orgpos += size + 1 51 | dstpos += size 52 | else: 53 | if c0 < 0xc0: # XY, backward Y+1, copy X-0x8+1 54 | offset = (c0&0xf) + 1 55 | size = (c0>>4) - 0x8 + 1 56 | orgpos += 1 57 | elif c0 < 0xe0: # XX YY, backward YY+1, copy XX-0xc0+2 58 | c1 = ykcmp.content[orgpos+1] 59 | offset = c1 + 1 60 | size = c0 - 0xc0 + 2 61 | orgpos += 2 62 | else: # XX XY YY, backward YYY+1, copy XXX-0xe00+3 63 | c1 = ykcmp.content[orgpos+1] 64 | c2 = ykcmp.content[orgpos+2] 65 | offset = ((c1&0xf)<<8) + c2 + 1 66 | size = ((c0<<4) + (c1>>4)) - 0xe00 + 3 67 | orgpos += 3 68 | resdata[dstpos: dstpos+size] = \ 69 | resdata[dstpos-offset: dstpos-offset+size] 70 | dstpos += size 71 | 72 | if dstpos!=ykcmp.rawsize: 73 | raise AssertionError(f"decompress size error!") 74 | if outpath!="": 75 | with open(outpath, 'wb') as fp: 76 | fp.write(resdata) 77 | return resdata 78 | 79 | def compress_ykcmpv1(data, outpath=""): 80 | ykcmp = ykcmp_t() 81 | _bufio = BytesIO() 82 | for i in range(0, len(data), 0x7f): 83 | size = 0x7f 84 | if i + size> len(data): size = len(data) - i 85 | _bufio.write(bytes([size])) 86 | _bufio.write(data[i: i+size]) 87 | 88 | ykcmp.content = _bufio.getbuffer() 89 | ykcmp.rawsize = len(data) 90 | ykcmp.ykcmpsize = 0x14 + len(ykcmp.content) 91 | resdata = ykcmp.tobytes() 92 | if outpath!="": 93 | with open(outpath, 'wb') as fp: 94 | fp.write(resdata) 95 | return resdata -------------------------------------------------------------------------------- /project/nippon1/src/yomawari3_switch_fad.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuriSizuku/GalgameReverse/e9e309986dd51ed65fc7c26c87de1d5f516cbc89/project/nippon1/src/yomawari3_switch_fad.py -------------------------------------------------------------------------------- /project/nippon1/src/yomawari3_switch_nltx.py: -------------------------------------------------------------------------------- 1 | """ 2 | A tool for exporting and importing nltx texture, tested by yonamwari3 3 | ntlx -> ykcmp -> nxswitexture 4 | developed by devseed, v0.1 5 | """ 6 | 7 | import sys 8 | import struct 9 | import numpy as np 10 | from PIL import Image 11 | import ykcmp 12 | 13 | def nxswi_deswizzle(x, y, image_width, bytes_per_pixel, base_addr, block_height): 14 | """ 15 | From the Tegra X1 TRM 16 | """ 17 | def DIV_ROUND_UP(n, d): 18 | return (n + d - 1) // d 19 | 20 | image_width_in_gobs = DIV_ROUND_UP(image_width * bytes_per_pixel, 64) 21 | gob_addr = (base_addr 22 | + (y//(8*block_height))*512*block_height*image_width_in_gobs 23 | + (x*bytes_per_pixel//64)*512*block_height 24 | + (y%(8*block_height)//8)*512) 25 | x *= bytes_per_pixel 26 | addr = (gob_addr + ((x % 64) // 32) * 256 + ((y % 8) // 2) * 64 27 | + ((x % 32) // 16) * 32 + (y % 2) * 16 + (x % 16)) 28 | return addr 29 | 30 | def decode_nxswitexure(data, imgw=0, imgh=0, blockh=16, outpath=""): 31 | """ 32 | decode switch R8_G8_B8_A8_UNORM texture with swizzle 33 | """ 34 | if imgw==0: imgw = np.int(np.sqrt(len(data)/4)) 35 | if imgh==0: imgh = np.int(np.sqrt(len(data)/4)) 36 | bgra =np.zeros((imgh, imgw, 4), dtype=np.uint8) 37 | if blockh==0: 38 | if imgw<=64 or imgh<=64: blockh=8 39 | else: blockh=16 40 | for x in range(imgw): 41 | for y in range(imgh): 42 | idx = nxswi_deswizzle(x, y, imgw, 4, 0, blockh) 43 | b, g, r, a = struct.unpack(' 2 | #include 3 | int decodeNT3(void *sh, char **buf, unsigned int size, FILE *fp) 4 | { 5 | int key; 6 | int tmp; 7 | int flag; 8 | char ch; 9 | char *cur; 10 | int data_size; 11 | 12 | if(size < 0x920) return -1; 13 | fseek(fp, 0x91C, 0); 14 | fread(&key, 4, 1, fp); 15 | data_size = fread(*buf, 1, size-0x920, fp); 16 | cur = *buf; 17 | if(data_size) 18 | { 19 | int i=1; 20 | int flag=1; 21 | do{ 22 | key ^= *cur; 23 | tmp = key + (*cur)*(data_size+1-i) + 0x5D588B65; 24 | key = tmp; 25 | *cur^=tmp; 26 | ch = *cur; 27 | if(ch=='*') 28 | { 29 | if(!flag) 30 | { 31 | i++; 32 | cur++; 33 | continue; 34 | } 35 | else 36 | { 37 | //++*((_DWORD *)this + 120); 38 | ch = *cur; 39 | } 40 | } 41 | if(ch != '\n') //10 42 | { 43 | if(!(ch==0x20 || ch== 9)) //SPACE, TAB 44 | flag=0; 45 | i++; 46 | cur++; 47 | continue; 48 | } 49 | flag = 1; 50 | i++; 51 | cur++; 52 | } 53 | while (data_size>=i); 54 | } 55 | *cur = 10; 56 | cur++; 57 | return 0; 58 | } 59 | 60 | int extractNT3(char *inpath, char *outpath) 61 | { 62 | FILE *fp = fopen(inpath, "rb"); 63 | fseek(fp, 0, SEEK_END); 64 | int size = ftell(fp); 65 | fseek(fp, 0, SEEK_SET); 66 | char *buf = malloc(size); 67 | memset(buf, 0, size); 68 | int ret = decodeNT3(NULL, &buf, size, fp); 69 | FILE *fp2 = fopen(outpath, "wb"); 70 | printf("%d", sizeof(buf)); 71 | fwrite(buf, sizeof(char), size, fp2); 72 | free(buf); 73 | fclose(fp); 74 | fclose(fp2); 75 | return ret; 76 | } 77 | 78 | int main(int argc, char **argv) 79 | { 80 | //FILE* fp = fopen(argv[0], "rb"); 81 | //decodeNT3(NULL,NULL ,0, fp); 82 | printf("extract onscript.nt3 (by devseed), extract_nt3 input [output]\n"); 83 | char *outpath; 84 | if(argc<=2) 85 | outpath = "result.txt"; 86 | else outpath = argv[2]; 87 | int ret = extractNT3(argv[1], outpath); 88 | if(ret==0) printf("%s extracted successfully!\n", outpath); 89 | else printf("%s extract faiiled!\n", outpath); 90 | return 0; 91 | } -------------------------------------------------------------------------------- /project/prototype/src/island_psv_pak.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import mmap 3 | import os 4 | import sys 5 | from io import BytesIO 6 | 7 | class Pak: 8 | def __init__(self, path=""): 9 | self.data = None 10 | # pak structure 11 | self.align = 0x0 # dword 12 | self.itemnum = 0x0 # dword 13 | self.itemidx = [] # (start offset, length) 14 | self.itemname = [] # most of 10byte strings end with \x00, 15 | self.items = [] #ITEM_STRUCT 16 | if path != "" : self.read_pak(path) 17 | 18 | 19 | def read_pak(self, path): 20 | f = os.open(path, os.O_BINARY) 21 | data = mmap.mmap(f, 0, access=mmap.ACCESS_READ) 22 | self.data = data 23 | self.align = struct.unpack('I', data[0x0:0x4])[0] 24 | self.itemnum = struct.unpack('I', data[0x4:0x8])[0] 25 | cur = 0x14 26 | for i in range(self.itemnum): 27 | self.itemidx.append(struct.unpack('II', data[cur:cur+0x8])) 28 | cur += 0x8 29 | for i in range(self.itemnum): 30 | end = data.find(b'\x00', cur) 31 | self.itemname.append(data[cur: end].decode('sjis')) 32 | cur = end + 1 33 | 34 | def extract(self, outdir=""): 35 | print("%d files to extract..." %self.itemnum) 36 | for i in range(self.itemnum): 37 | with open(os.path.join(outdir, self.itemname[i]), 'wb') as f: 38 | f.write(self.data[self.itemidx[i][0] : self.itemidx[i][0] + self.itemidx[i][1]]) 39 | print(self.itemidx[i][0], self.itemidx[i][0] + self.itemidx[i][1], self.itemname[i], "extracted! ") 40 | 41 | def repack(self, indir, outpath): 42 | files = os.listdir(indir) 43 | data = BytesIO() 44 | cur = self.itemidx[0][0] 45 | align = self.align 46 | for i, name in enumerate(self.itemname): 47 | if name in files: 48 | with open(os.path.join(indir, name), 'rb') as fp: 49 | _data = fp.read() 50 | data.write(_data) 51 | if len(_data) % align != 0: 52 | data.write(b'\x00' * (align -len(_data) % align)) 53 | size = len(_data) + align - len(_data) % align 54 | else: size = len(_data) 55 | print("%s (%x, %x) -> (%x, %x)" % (name, self.itemidx[i][0], self.itemidx[i][1], cur, len(_data))) 56 | self.itemidx[i] = (cur, len(_data)) 57 | 58 | else: 59 | data.write(self.data[self.itemidx[i][0] : self.itemidx[i][0] + self.itemidx[i][1]]) 60 | if self.itemidx[i][1] % align != 0: 61 | data.write(b'\x00' * (align -self.itemidx[i][1] % align)) 62 | size =self.itemidx[i][1] + align - self.itemidx[i][1] % align 63 | else: size = self.itemidx[i][1] 64 | self.itemidx[i] = (cur, self.itemidx[i][1]) 65 | cur += size 66 | 67 | with open(outpath, 'wb') as fp: 68 | fp.write(struct.pack(' 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | #define WIVERSION_VERSION 100 14 | 15 | #ifdef USECOMPAT 16 | #include "commdef_v110.h" 17 | #else 18 | #include "commdef.h" 19 | #endif // USECOMPAT 20 | 21 | // macro and global declear 22 | static HMODULE s_winversion = NULL; 23 | #if defined(_MSC_VER) 24 | // https://github.com/BitCrackers/version-proxy/blob/main/src/version.cpp 25 | #ifdef _M_AMD64 // msvc x64 26 | #pragma warning (disable: 4081) 27 | #define STRINGIFY(name) #name 28 | #define EXPORT_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) 29 | #define WINVERSION_WRAP_FUNC(name) \ 30 | FARPROC s_##name; \ 31 | __declspec(dllexport) void WINAPI __wrap_##name() \ 32 | { \ 33 | __pragma(STRINGIFY(EXPORT_FUNCTION)); \ 34 | s_##name(); \ 35 | } 36 | #else // msvc x86 37 | #define WINVERSION_WRAP_FUNC(name) \ 38 | static FARPROC s_##name; \ 39 | __declspec(naked) void __wrap_##name() \ 40 | { \ 41 | __asm jmp[s_##name] \ 42 | } 43 | #endif 44 | #else // gcc 45 | #define WINVERSION_WRAP_FUNC(name) \ 46 | static FARPROC s_##name = NULL; \ 47 | EXPORT NAKED void __wrap_##name () \ 48 | {\ 49 | asm volatile("jmp *%0" : : "m" (s_##name)); \ 50 | } 51 | 52 | #endif // _MSC_VER 53 | #define WINVERSION_BIND_FUNC(name) s_##name = GetProcAddress(s_winversion, #name); 54 | 55 | // export function define 56 | WINVERSION_WRAP_FUNC(GetFileVersionInfoA) 57 | WINVERSION_WRAP_FUNC(GetFileVersionInfoByHandle) 58 | WINVERSION_WRAP_FUNC(GetFileVersionInfoExW) 59 | WINVERSION_WRAP_FUNC(GetFileVersionInfoExA) 60 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeA) 61 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeExW) 62 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeExA) 63 | WINVERSION_WRAP_FUNC(GetFileVersionInfoSizeW) 64 | WINVERSION_WRAP_FUNC(GetFileVersionInfoW) 65 | WINVERSION_WRAP_FUNC(VerFindFileA) 66 | WINVERSION_WRAP_FUNC(VerFindFileW) 67 | WINVERSION_WRAP_FUNC(VerInstallFileA) 68 | WINVERSION_WRAP_FUNC(VerInstallFileW) 69 | WINVERSION_WRAP_FUNC(VerLanguageNameA) 70 | WINVERSION_WRAP_FUNC(VerLanguageNameW) 71 | WINVERSION_WRAP_FUNC(VerQueryValueA) 72 | WINVERSION_WRAP_FUNC(VerQueryValueW) 73 | 74 | static void winversion_init() 75 | { 76 | // origin version path 77 | char versionpath[MAX_PATH]; 78 | GetSystemDirectoryA(versionpath, MAX_PATH); 79 | strcat(versionpath, "\\version.dll"); 80 | s_winversion = LoadLibraryA(versionpath); 81 | 82 | // bind version apis 83 | WINVERSION_BIND_FUNC(GetFileVersionInfoA); 84 | WINVERSION_BIND_FUNC(GetFileVersionInfoByHandle); 85 | WINVERSION_BIND_FUNC(GetFileVersionInfoExW); 86 | WINVERSION_BIND_FUNC(GetFileVersionInfoExA); 87 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeA); 88 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeExW); 89 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeExA); 90 | WINVERSION_BIND_FUNC(GetFileVersionInfoSizeW); 91 | WINVERSION_BIND_FUNC(GetFileVersionInfoW); 92 | WINVERSION_BIND_FUNC(VerFindFileA); 93 | WINVERSION_BIND_FUNC(VerFindFileW); 94 | WINVERSION_BIND_FUNC(VerInstallFileA); 95 | WINVERSION_BIND_FUNC(VerInstallFileW); 96 | WINVERSION_BIND_FUNC(VerLanguageNameA); 97 | WINVERSION_BIND_FUNC(VerLanguageNameW); 98 | WINVERSION_BIND_FUNC(VerQueryValueA); 99 | WINVERSION_BIND_FUNC(VerQueryValueW); 100 | } 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | #endif -------------------------------------------------------------------------------- /project/qt/src/qfile_dump.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * dynamic dump qt5 res vfs 3 | * v0.1, devloped by devseed 4 | * 5 | * usage: 6 | * put the compiled version.dll to game dir and run the game 7 | * 8 | * tested games: 9 | * 叙事曲1:难忘的回忆 10 | * 叙事曲2:星空下的诺言 11 | * 12 | * acknowledgement: 13 | * https://github.com/Dir-A 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef USECOMPAT 22 | #include "winversion_v100.h" 23 | #else 24 | #include "winversion.h" 25 | #endif 26 | 27 | #define DUMP_DIR L"dump" 28 | 29 | static DWORD WINAPI _dump_dir(QDir qdir, DWORD *pn) 30 | { 31 | for(auto t: qdir.entryInfoList()) 32 | { 33 | QString outpath = QString::fromStdWString(DUMP_DIR + t.absoluteFilePath().toStdWString().substr(1)); 34 | if(t.isDir()) 35 | { 36 | static wchar_t tmppathw[MAX_PATH]; 37 | wcscpy(tmppathw, outpath.toStdWString().c_str()); 38 | CreateDirectoryW(tmppathw, NULL); 39 | _dump_dir(t.absoluteFilePath(), pn); 40 | } 41 | else 42 | { 43 | // prepare data 44 | QFile infile(t.absoluteFilePath()); 45 | LOGLi(L"%ld path=%ls size=0x%zx\n", 46 | ++(*pn), t.absoluteFilePath().toStdWString().c_str(), 47 | infile.size()); 48 | infile.open(QIODevice::ReadOnly); 49 | auto data = infile.readAll(); 50 | infile.close(); 51 | 52 | // save data to file 53 | QFile outfile(outpath); 54 | outfile.open(QIODevice::WriteOnly); 55 | outfile.write(data); 56 | outfile.close(); 57 | } 58 | } 59 | return *pn; 60 | } 61 | 62 | static DWORD WINAPI dump_dir(void *args) 63 | { 64 | // Sleep(1000); 65 | DWORD count = 0; 66 | QDir qdir(":/"); 67 | CreateDirectoryW(DUMP_DIR L"/", NULL); 68 | count = _dump_dir(qdir, &count); 69 | LOGi("dump finished with %d files \n", count); 70 | return 0; 71 | } 72 | 73 | static void init() 74 | { 75 | AllocConsole(); 76 | freopen("CONOUT$", "w", stdout); 77 | // system("chcp 936"); 78 | // setlocale(LC_ALL, "chs"); 79 | printf("qt5_dump res, v0.1, developed by devseed\n"); 80 | DWORD winver = GetVersion(); 81 | DWORD winver_major = (DWORD)(LOBYTE(LOWORD(winver))); 82 | DWORD winver_minor = (DWORD)(HIBYTE(LOWORD(winver))); 83 | LOGi("version NT=%lu.%lu\n", winver_major, winver_minor); 84 | #if defined(_MSC_VER) 85 | LOGi("compiler MSVC=%d\n", _MSC_VER) 86 | #elif defined(__GNUC__) 87 | LOGi("compiler GNUC=%d.%d\n", __GNUC__, __GNUC_MINOR__); 88 | #elif defined(__TINYC__) 89 | LOGi("compiler TCC\n"); 90 | #endif 91 | 92 | CreateThread(NULL, 0, dump_dir, NULL, 0, NULL); 93 | } 94 | 95 | extern "C" EXPORT void dummy() 96 | { 97 | 98 | } 99 | 100 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ) 101 | { 102 | switch( fdwReason ) 103 | { 104 | case DLL_PROCESS_ATTACH: 105 | winversion_init(); 106 | init(); 107 | break; 108 | case DLL_THREAD_ATTACH: 109 | break; 110 | case DLL_THREAD_DETACH: 111 | break; 112 | case DLL_PROCESS_DETACH: 113 | break; 114 | } 115 | return TRUE; 116 | } 117 | -------------------------------------------------------------------------------- /project/renpy/src/skyblue_wjz.py: -------------------------------------------------------------------------------- 1 | """ 2 | extract *.blend file for The Other Side of the Sky 3 | v0.1, developed by devseed 4 | """ 5 | 6 | import os 7 | import sys 8 | import io 9 | import zlib 10 | import mmap 11 | import pickle 12 | 13 | # pickle.py 14 | PROTOCOL = 2 15 | REWRITE_NODES = {} 16 | import functools 17 | import datetime 18 | 19 | def make_datetime(cls, *args, **kwargs): 20 | """ 21 | Makes a datetime.date, datetime.time, or datetime.datetime object 22 | from a surrogateescaped str. This is used when unpickling a datetime 23 | object that was first created in Python 2. 24 | """ 25 | 26 | if (len(args) == 1) and isinstance(args[0], str): 27 | data = args[0].encode("utf-8", "surrogateescape") 28 | return cls.__new__(cls, data.decode("latin-1")) 29 | 30 | return cls.__new__(cls, *args, **kwargs) 31 | 32 | class Unpickler(pickle.Unpickler): 33 | date = functools.partial(make_datetime, datetime.date) 34 | time = functools.partial(make_datetime, datetime.time) 35 | datetime = functools.partial(make_datetime, datetime.datetime) 36 | 37 | def find_class(self, module, name): 38 | if module == "datetime": 39 | if name == "date": 40 | return self.date 41 | elif name == "time": 42 | return self.time 43 | elif name == "datetime": 44 | return self.datetime 45 | 46 | if module == "_ast" and name in REWRITE_NODES: 47 | return REWRITE_NODES[name] 48 | 49 | return super().find_class(module, name) 50 | 51 | def load(f): 52 | up = Unpickler(f, fix_imports=True, encoding="utf-8", errors="surrogateescape") 53 | return up.load() 54 | 55 | def loads(s): 56 | return load(io.BytesIO(s)) 57 | 58 | def dump(o, f, highest=False): 59 | pickle.dump(o, f, pickle.HIGHEST_PROTOCOL if highest else PROTOCOL) 60 | 61 | def dumps(o, highest=False): 62 | return pickle.dumps(o, pickle.HIGHEST_PROTOCOL if highest else PROTOCOL) 63 | 64 | # loader.py 65 | class RPAv3ArchiveHandler(object): 66 | """ 67 | Archive handler handling RPAv3 archives. 68 | """ 69 | 70 | archive_extension = ".blend" 71 | 72 | @staticmethod 73 | def get_supported_extensions(): 74 | return [ ".blend" ] 75 | 76 | @staticmethod 77 | def get_supported_headers(): 78 | return [ b"WJZ-4.9 " ] 79 | 80 | @staticmethod 81 | def read_index(infile: io.BytesIO) -> dict: 82 | l = infile.read(40) 83 | offset = int(l[8:24], 16) 84 | key = int(l[25:33], 16) 85 | infile.seek(offset) 86 | index = loads(zlib.decompress(infile.read())) 87 | 88 | def start_to_bytes(s): 89 | if not s: 90 | return b'' 91 | 92 | if not isinstance(s, bytes): 93 | s = s.encode("latin-1") 94 | 95 | return s 96 | 97 | # Deobfuscate the index. 98 | for k in index.keys(): 99 | if len(index[k][0]) == 2: 100 | index[k] = [ (offset ^ key, dlen ^ key) for dlen, offset in index[k] ] 101 | else: 102 | index[k] = [ (offset ^ key, dlen ^ key, start_to_bytes(start)) for dlen, offset, start in index[k] ] 103 | 104 | return index 105 | 106 | def extract_wjz(inpath, outdir="out"): 107 | fp = open(inpath, "rb") 108 | infile = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) 109 | index = RPAv3ArchiveHandler.read_index(infile) 110 | 111 | for entry_name, v in index.items(): 112 | outpath = os.path.join(outdir, entry_name) 113 | if not os.path.exists(os.path.dirname(outpath)) : 114 | os.makedirs(os.path.dirname(outpath)) 115 | with open(outpath, "wb") as fp2: 116 | for j, (offset, fsize, uknow) in enumerate(v): 117 | print(f"{entry_name} chunck={j} offset=0x{offset:x} fsize=0x{fsize:x}") 118 | fp2.write(infile[offset: offset + fsize]) 119 | 120 | infile.close() 121 | fp.close() 122 | 123 | def debug(): 124 | pass 125 | 126 | def cli(argv=sys.argv): 127 | if len(argv) < 2: 128 | print("skyblue_wjz inpath [outdir] // inpath wjz *.blend") 129 | 130 | inpath = argv[1] 131 | outdir = argv[2] if len(argv) > 2 else os.path.dirname(inpath) 132 | 133 | extract_wjz(inpath, outdir) 134 | 135 | if __name__ == "__main__": 136 | cli() -------------------------------------------------------------------------------- /project/systemnnn/systemnnn.mk: -------------------------------------------------------------------------------- 1 | # make -f systemnnn.mk CC=/opt/llvm-mingw/bin/i686-w64-mingw32-clang # llvm 18.1.8 2 | # make -f systemnnn.mk CC=i686-w64-mingw32-gcc # gcc 12 3 | 4 | CC:=clang 5 | BUILD_DIR:=asset/build 6 | INCS:=-Isrc/compat 7 | LIBS:=-luser32 -lgdi32 -lshlwapi -ladvapi32 -lpsapi 8 | CFLAGS:=-ffunction-sections -fdata-sections 9 | LDFLAGS:= 10 | 11 | ifdef DEBUG 12 | CFLAGS+=-g -D_DEBUG 13 | else 14 | CFLAGS+=-Os 15 | endif 16 | ifneq (,$(wildcard src/compat/*)) 17 | CFLAGS+=-DUSECOMPAT 18 | endif 19 | 20 | ifneq (,$(findstring clang, $(CC))) # for llvm-mingw 21 | CFLAGS+=-m32 22 | ifndef NOPDB 23 | CFLAGS+=-gcodeview -Wl,--pdb=$(BUILD_DIR)/systemnnn_patch.pdb 24 | endif 25 | LDFLAGS+= -Wl,--gc-sections 26 | else ifneq (,$(findstring gcc, $(CC))) # for mingw-w64 27 | CFLAGS+=-m32 28 | LDFLAGS+= -Wl,--gc-sections \ 29 | -static-libgcc -static-libstdc++ \ 30 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 31 | -Wl,--no-whole-archive 32 | else ifneq (,$(findstring tcc, $(CC))) # for tcc 33 | CFLAGS+=-m32 34 | else # for previous llvm clang with msvc 35 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 36 | LDFLAGS+=-Wl,/OPT:REF # for llvm 37 | endif 38 | 39 | all: prepare systemnnn_patch 40 | 41 | prepare: 42 | @mkdir -p $(BUILD_DIR) 43 | 44 | systemnnn_patch: src/systemnnn_patch.c 45 | @echo "## $@" 46 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 47 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 48 | @rm -rf $(BUILD_DIR)/$@.exp 49 | @rm -rf $(BUILD_DIR)/$@.lib 50 | @rm -rf $(BUILD_DIR)/$@.def 51 | 52 | .PHONY: prepare systemnnn_patch -------------------------------------------------------------------------------- /project/systemnnn/task/task_wajinIbunroku/Makefile: -------------------------------------------------------------------------------- 1 | # required variables: 2 | # WORK_DIR, build workflow dir 3 | # SRC_DIR, project src dir, usually ../../src 4 | # TOOL_DIR, external tool dir, usually ../../tool 5 | 6 | # optional variables 7 | # BASE_DIR, project basedir 8 | # GAME_EXEC, use which command to launch game 9 | # GAME_FILE, origin game package path 10 | # GAME_DIR, game dir for testing 11 | # MINGWSDK, llvm-mingw path 12 | 13 | # usage: 14 | # in linux, "source ./_env.sh" 15 | # in windows, "msys2_shell -here -no-start -defterm -full-path" to activate, then "source ./_env.sh" 16 | 17 | # _env.sh example 18 | # export GAME_NAME=WajinIbunroku 19 | # export GAME_ID=vndb-v11340 20 | # if [ -n "$(uname -a | grep Msys)" ]; then 21 | # export BASE_DIR=/d/Downloads/$GAME_NAME 22 | # export GAME_EXEC=start 23 | # export MINGWSDK=/d/Software/env/llvm-mingw 24 | # else 25 | # LOCPATH=~/.wine/locale 26 | # if ! [ -d $LOCPATH/zh_CN.UTF-8 ]; then 27 | # mkdir -p $LOCPATH 28 | # localedef -f UTF-8 -i zh_CN $LOCPATH/zh_CN.UTF-8 29 | # fi 30 | # export BASE_DIR=~/Downloads/$GAME_NAME 31 | # export GAME_EXEC=LOCPATH=$LOCPATH\ LANG=zh_CN.UTF-8\ wine 32 | # export MINGWSDK=/opt/llvm-mingw 33 | # fi 34 | # export GAME_FILE=$BASE_DIR/${GAME_ID}.7z 35 | # export GAME_DIR=$BASE_DIR/${GAME_ID}_rebuild 36 | # export WORK_DIR=$BASE_DIR/workflow 37 | # export SRC_DIR=../../src 38 | # export TOOL_DIR=../../tool 39 | 40 | all: 41 | @echo build Sorairo chspatch 42 | @make build_1txt 43 | @make build_1spt 44 | @make build_2dwq 45 | @make build_3dll 46 | @make build_3exe 47 | 48 | link: 49 | @if ! [ -d workflow ]; then \ 50 | ln -s $(WORKFLOW_DIR) workflow;\ 51 | fi 52 | 53 | unlink: 54 | @rm -rf workflow 55 | 56 | init_workdir init_gamedir init_mingwsdk: 57 | @./init.sh $@ 58 | 59 | build_1txt build_1spt build_2dwq build_3dll build_3exe: init_workdir 60 | @./build.sh $@ 61 | 62 | release_patch: 63 | @./build.sh $@ 64 | 65 | # wine need 66 | # sudo apt install gstreamer1.0-libav:i386 67 | # sudo apt install gstreamer1.0-plugins-bad:i386 68 | # sudo apt install gstreamer1.0-plugins-base:i386 69 | # sudo apt install gstreamer1.0-plugins-good:i386 70 | run: 71 | @cd $(GAME_DIR);$(GAME_EXEC) wajin_asaki_chs.exe 72 | 73 | # vscode launch.json config 74 | # can not pause while running, can only set breakpoint on pause or before launch 75 | # "name": "linux wajin_asaki", 76 | # "type": "cppdbg", 77 | # "request": "launch", 78 | # "program": "wajin_asaki_chs.exe", 79 | # "args": [], 80 | # "cwd": "~/Downloads/WajinIbunroku/vndb-v11340_rebuild/", 81 | # "stopAtEntry": false, 82 | # "environment": [], 83 | # "MIMode": "gdb", 84 | # "miDebuggerPath": "/usr/bin/i686-w64-mingw32-gdb", 85 | # "miDebuggerServerAddress": "localhost:1234", 86 | run_gdbserver: 87 | @cd $(GAME_DIR); LOCPATH=~/.wine/locale LANG=zh_CN.UTF-8 \ 88 | wine Z:/usr/share/win32/gdbserver.exe localhost:1234 wajin_asaki_chs.exe 89 | 90 | send: init_gamedir 91 | @cp -rf $(WORK_DIR)/5.result/* $(GAME_DIR) 92 | 93 | test: 94 | @make send 95 | @make run 96 | 97 | clean: 98 | @rm -f $(WORK_DIR)/*.7z 99 | @rm -rf ${WORK_DIR}/5.result 100 | 101 | .PHONY: all link unlink \ 102 | init_workdir init_gamedir init_mingwsdk \ 103 | build_1txt build_1spt build_2dwq build_3dll build_3exe \ 104 | release_patch run run_gdbserver send test clean -------------------------------------------------------------------------------- /project/systemnnn/task/task_wajinIbunroku/build.sh: -------------------------------------------------------------------------------- 1 | build_1txt() { 2 | echo "## build_1init" 3 | 4 | echo "## build fxf" 5 | ./init.sh encode_fxf ${WORK_DIR}/3.edit/init2_txt ${WORK_DIR}/5.result/override/init2 6 | # ./init.sh encode_fxf ${WORK_DIR}/3.edit/spt_txt ${WORK_DIR}/5.result/override/spt 7 | 8 | echo "## build xtx" 9 | for infile in $(ls ${WORK_DIR}/3.edit/nya_txt/*.xtx.txt); do 10 | inname=$(basename $infile ".txt") 11 | echo $inname 12 | cp -f $infile ${WORK_DIR}/5.result/override/nya/$inname 13 | done 14 | for infile in $(ls ${WORK_DIR}/3.edit/spt_txt/*.xtx.txt); do 15 | inname=$(basename $infile) 16 | echo $inname 17 | cp -f $infile ${WORK_DIR}/5.result/override/spt/$inname 18 | done 19 | } 20 | 21 | build_1spt() { 22 | echo "## build_1spt" 23 | for infile in $(ls ${WORK_DIR}/3.edit/spt_ftext/*.txt); do 24 | inname=$(basename $infile ".txt") 25 | echo $inname 26 | python $SRC_DIR/systemnnn_spt.py i \ 27 | ${WORK_DIR}/1.origin/spt/$inname -t $infile --encoding gbk \ 28 | -o ${WORK_DIR}/5.result/override/spt/$inname 29 | done 30 | } 31 | 32 | build_2dwq() { 33 | echo "## build_2dwq" 34 | if [ -f ${WORK_DIR}/3.edit/dwq_png/*.png ]; then 35 | cp -f ${WORK_DIR}/3.edit/dwq_png/*.png ${WORK_DIR}/5.result/override/png 36 | fi 37 | } 38 | 39 | build_3dll() { 40 | echo "## build_3dll" 41 | if [ -z "$CC" ]; then CC=$MINGWSDK/bin/i686-w64-mingw32-clang; fi 42 | make -C ${SRC_DIR}/../ -f systemnnn.mk CC=$CC BUILD_DIR=${WORK_DIR}/5.result 43 | } 44 | 45 | build_3exe() { 46 | echo "## build_3exe" 47 | python -B ${SRC_DIR}/compat/windllin_v321.py -m codecave2 \ 48 | ${WORK_DIR}/1.origin/wajin_asaki.exe systemnnn_patch.dll \ 49 | -o ${WORK_DIR}/5.result/wajin_asaki_chs.exe 1>/dev/null 50 | echo "charset=134" > ${WORK_DIR}/5.result/override/config.ini 51 | echo "font=simhei" >> ${WORK_DIR}/5.result/override/config.ini 52 | echo "patch=+3DC17:FE" >> ${WORK_DIR}/5.result/override/config.ini 53 | echo "CPicture_LoadDWQ=939744" >> ${WORK_DIR}/5.result/override/config.ini 54 | echo "CPicture_mpic=32" >> ${WORK_DIR}/5.result/override/config.ini 55 | } 56 | 57 | release_patch() { 58 | echo "## release_patch"W 59 | RELEASE_NAME="[$(date +"%y%m%d")build][${GAME_ID}]${GAME_NAME}_${VERSION}[1CHSPATCH]" 60 | RELEASE_FILE=${WORK_DIR}/$RELEASE_NAME.7z 61 | RELEASE_DIR=${WORK_DIR}/5.result 62 | echo $RELEASE_NAME 63 | 7z a -mx5 $RELEASE_FILE $RELEASE_DIR 64 | 7z rn $RELEASE_FILE $(basename $RELEASE_DIR) $RELEASE_NAME 65 | } 66 | 67 | $* -------------------------------------------------------------------------------- /project/tyrano/make_tyrano_extractexe.bat: -------------------------------------------------------------------------------- 1 | clang -target i686-pc-windows-msvc ./tyrano_extractexe.c -o ./build/tyrano_extractexe.exe -D_CRT_SECURE_NO_WARNINGS -------------------------------------------------------------------------------- /project/tyrano/src/make_tyrano_extractexe.bat: -------------------------------------------------------------------------------- 1 | clang -target i686-pc-windows-msvc ./tyrano_extractexe.c -o ./build/tyrano_extractexe.exe -D_CRT_SECURE_NO_WARNINGS -------------------------------------------------------------------------------- /project/tyrano/src/qbit_hook_obb.py: -------------------------------------------------------------------------------- 1 | import frida, sys 2 | jscode = """ 3 | console.log('on the start!') 4 | Java.perform(function(){ 5 | var MainActivity = Java.use("jp.tyrano.tyranoplayerframework.MainActivity"); 6 | MainActivity.onPause.overload() 7 | .implementation = function() { 8 | try{ 9 | var JString = Java.use("java.lang.String"); 10 | var JFile = Java.use("java.io.File") 11 | var JFileInPutStream = Java.use("java.io.FileInputStream"); 12 | var JFileOutPutStream = Java.use("java.io.FileOutputStream"); 13 | 14 | var obbpath = this.getMountedObbPath(); 15 | console.log("obb mounted at: " + obbpath); 16 | // no need to use this, mount directly to copy out in shell 17 | //var outpath = "/sdcard/1.txt"; 18 | //var inpath = obbpath + "/data/video/qbt.webm"; 19 | /var fin = JFile.$new(outpath); 20 | //var fout = JFile.$new(inpath); 21 | //var out = JFileOutPutStream.$new(file); 22 | 23 | } catch (e) { 24 | console.log(e.message) 25 | } 26 | return this.onPause(); 27 | } 28 | }); 29 | 30 | """ 31 | 32 | def on_message(message, data): 33 | print(message) 34 | 35 | device = frida.get_usb_device(1) # make higher timeout 36 | #pid = device.spawn('jp.q_bit.a01t') 37 | session = device.attach('jp.q_bit.a01t') 38 | #session = device.attach(pid) 39 | script = session.create_script(jscode) 40 | script.on('message', on_message) 41 | script.load() 42 | sys.stdin.read() -------------------------------------------------------------------------------- /project/tyrano/src/tyrano_extractexe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _WIN64 5 | #define ADDR_TYPE DWORD 6 | #else 7 | #define ADDR_TYPE ULONGLONG 8 | #endif 9 | #define MAX_BUF 0x1000 10 | 11 | size_t getOverlayRawoffset(BYTE *pe) 12 | { 13 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pe; 14 | 15 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS) 16 | ((ADDR_TYPE)pe + pDosHeader->e_lfanew); 17 | PIMAGE_FILE_HEADER pFileHeader = &pNtHeader->FileHeader; 18 | PIMAGE_OPTIONAL_HEADER pOptHeader = &pNtHeader->OptionalHeader; 19 | PIMAGE_DATA_DIRECTORY pDataDirectory = pOptHeader->DataDirectory; 20 | 21 | PIMAGE_SECTION_HEADER pSectHeader = (PIMAGE_SECTION_HEADER) 22 | ((ADDR_TYPE)pOptHeader + pFileHeader->SizeOfOptionalHeader); 23 | WORD sectNum = pFileHeader->NumberOfSections; 24 | 25 | // printf("pNtHeader = %llx\n", (ADDR_TYPE)pNtHeader - (ADDR_TYPE)pe); 26 | // printf("pSectHeader = %llx\n", (ADDR_TYPE)pSectHeader - (ADDR_TYPE)pe); 27 | // printf("lastsect PointerToRawData=%lx, SizeOfRawData=%lx\n", 28 | // pSectHeader[sectNum-1].PointerToRawData, 29 | // pSectHeader[sectNum-1].SizeOfRawData); 30 | return pSectHeader[sectNum-1].PointerToRawData + 31 | pSectHeader[sectNum-1].SizeOfRawData; 32 | } 33 | 34 | void extractOverlay(const char *inpath, const char *outpath) 35 | { 36 | BYTE buf[MAX_BUF]; 37 | FILE* fpin = fopen(inpath, "rb"); 38 | FILE* fpout = fopen(outpath, "wb"); 39 | 40 | fread(buf, MAX_BUF, 1, fpin); 41 | size_t offset = getOverlayRawoffset(buf); 42 | //printf("overlay offset at %zx\n", offset); 43 | fseek(fpin, offset, SEEK_SET); 44 | int ch; 45 | while((ch=fgetc(fpin))!=EOF) 46 | { 47 | fputc(ch, fpout); 48 | } 49 | fclose(fpout); 50 | fclose(fpin); 51 | } 52 | 53 | int main(int argc, char *argv[]) 54 | { 55 | printf("A tool to extract tyrano build-in exe files, by devseed\n"); 56 | if(argc<2) 57 | { 58 | printf("tyrano_extract_exe exepath [outpath]\n"); 59 | } 60 | char outpath[MAX_BUF]; 61 | if(argc<3) 62 | { 63 | strcpy(outpath, argv[1]); 64 | strcat(outpath, ".zip"); 65 | } 66 | else 67 | { 68 | strcpy(outpath, argv[2]); 69 | } 70 | printf("to extract %s ...\n", argv[1]); 71 | extractOverlay(argv[1], outpath); 72 | printf("extract to %s finished!\n", outpath); 73 | } -------------------------------------------------------------------------------- /project/yuris/akaihana.mk: -------------------------------------------------------------------------------- 1 | BUILD_DIR:=./asset/build 2 | INCS:= 3 | LIBDIRS:= 4 | LIBS:=-luser32 -lgdi32 5 | CFLAGS:=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE \ 6 | -ffunction-sections -fdata-sections -D_DEBUG -g 7 | LDFLAGS:=-Wl,/OPT:REF 8 | 9 | all: akaihana_patch 10 | 11 | akaihana_patch: src/akaihana_patch.c 12 | clang -shared $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) $^ -o $(BUILD_DIR)/$@.dll -Os 13 | rm -rf $(BUILD_DIR)/$@.exp 14 | rm -rf $(BUILD_DIR)/$@.lib 15 | 16 | .PHONY: akaihana_patch -------------------------------------------------------------------------------- /project/yuris/yuris.mk: -------------------------------------------------------------------------------- 1 | # make -f yuris.mk CC=/opt/llvmmingw/bin/i686-w64-mingw32-clang # llvm 18.1.8 2 | # make -f yuris.mk CC=i686-w64-mingw32-gcc # gcc 12 3 | 4 | CC:=clang 5 | BUILD_DIR:=asset/build 6 | INCS:=-Isrc/compat 7 | LIBS:=-luser32 -lgdi32 -lshlwapi -ladvapi32 -lpsapi 8 | CFLAGS:=-ffunction-sections -fdata-sections -Wno-format 9 | LDFLAGS:= 10 | 11 | ifdef DEBUG 12 | CFLAGS+=-g -D_DEBUG 13 | else 14 | CFLAGS+=-Os 15 | endif 16 | ifneq (,$(wildcard src/compat/*)) 17 | CFLAGS+=-DUSECOMPAT 18 | endif 19 | ifneq (,$(wildcard src/compat/dvfs/*.h)) 20 | CFLAGS+=-DUSEWINDVFS 21 | endif 22 | 23 | ifneq (,$(findstring clang, $(CC))) # for llvm-mingw 24 | CFLAGS+=-m32 -gcodeview -Wl,--pdb=$(BUILD_DIR)/yuris_patch.pdb 25 | LDFLAGS+= -Wl,--gc-sections 26 | else ifneq (,$(findstring gcc, $(CC))) # for mingw-w64 27 | CFLAGS+=-m32 28 | LDFLAGS+= -Wl,--gc-sections \ 29 | -static-libgcc -static-libstdc++ \ 30 | -Wl,-Bstatic,--whole-archive -lwinpthread \ 31 | -Wl,--no-whole-archive 32 | else ifneq (,$(findstring tcc, $(CC))) # for tcc 33 | CFLAGS+=-m32 34 | else # for previous llvm clang with msvc 35 | CFLAGS+=-target i686-pc-windows-msvc -D _CRT_SECURE_NO_DEPRECATE 36 | LDFLAGS+=-Wl,/OPT:REF # for llvm 37 | endif 38 | 39 | all: prepare yuris_patch 40 | 41 | prepare: 42 | @mkdir -p $(BUILD_DIR) 43 | 44 | yuris_patch: src/yuris_patch.c 45 | @echo "## $@" 46 | $(CC) -shared $^ -o $(BUILD_DIR)/$@.dll \ 47 | $(INCS) $(LIBDIRS) $(LIBS) $(CFLAGS) $(LDFLAGS) 48 | @rm -rf $(BUILD_DIR)/$@.exp 49 | @rm -rf $(BUILD_DIR)/$@.lib 50 | @rm -rf $(BUILD_DIR)/$@.def 51 | 52 | .PHONY: prepare yuris_patch --------------------------------------------------------------------------------