mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2026-09-15 03:45:09 -05:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db12f21fd2 | ||
|
|
d009502c9f | ||
|
|
aa147022c6 | ||
|
|
8bcadcfa8f | ||
|
|
993e6718b3 | ||
|
|
2939106841 | ||
|
|
91bb3b4278 | ||
|
|
9c49839e57 | ||
|
|
52d907e0c6 | ||
|
|
f8a09580ea | ||
|
|
6e06685551 |
@@ -2,6 +2,11 @@
|
||||
Note for CI/CD: Ensure the version formatting in the sections is kept identical to the versions
|
||||
given in tags. The pipeline will pick this up and cuts out the relevant section for release notes.
|
||||
|
||||
## 5.41
|
||||
* Feature: Support pop'n music 15-18 using popnhook1
|
||||
* Feature: Support IIDX tricoro CN using iidxhook5-cn
|
||||
* Various documentation improvements
|
||||
|
||||
## 5.40
|
||||
* Feature: Support DDR X and X2 US/EU using ddrhook1 including memory card emulation
|
||||
* Fix: sdvxhook2 crashing on some OS versions
|
||||
|
||||
@@ -29,4 +29,4 @@ COPY src src
|
||||
COPY .git .git
|
||||
|
||||
# Building
|
||||
RUN make
|
||||
RUN make
|
||||
|
||||
53
Module.mk
53
Module.mk
@@ -21,12 +21,19 @@
|
||||
#
|
||||
# 4: Patch 2: beatmania IIDX 14 GOLD
|
||||
#
|
||||
# 4: Patch 3: pop'n music 15 ADVENTURE
|
||||
#
|
||||
# 6: Patch 5: beatmania IIDX 15 DJ Troopers
|
||||
#
|
||||
# 7: Patch 1: pop'n music 16 PARTY
|
||||
#
|
||||
# 8: Patch 3: beatmania IIDX 16 Empress
|
||||
# jubeat
|
||||
#
|
||||
# 10: Patch 2: jubeat Knit
|
||||
# 9: Patch 0: pop'n music 17 THE MOVIE
|
||||
#
|
||||
# 10: Patch 1: pop'n music 18 Sengoku Retsuden
|
||||
# Patch 2: jubeat Knit
|
||||
# Patch 4: DanceDanceRevolution X2
|
||||
#
|
||||
# 11: Patch 1: beatmania IIDX 18 Resort Anthem
|
||||
@@ -113,6 +120,8 @@ include src/main/ezusb2-dbg-hook/Module.mk
|
||||
include src/main/ezusb2-emu/Module.mk
|
||||
include src/main/ezusb2-iidx-emu/Module.mk
|
||||
include src/main/ezusb2-iidx/Module.mk
|
||||
include src/main/ezusb2-popn-emu/Module.mk
|
||||
include src/main/ezusb2-popn-shim/Module.mk
|
||||
include src/main/ezusb2-tool/Module.mk
|
||||
include src/main/ezusb2/Module.mk
|
||||
include src/main/geninput/Module.mk
|
||||
@@ -128,6 +137,7 @@ include src/main/iidxhook2/Module.mk
|
||||
include src/main/iidxhook3/Module.mk
|
||||
include src/main/iidxhook4/Module.mk
|
||||
include src/main/iidxhook5/Module.mk
|
||||
include src/main/iidxhook5-cn/Module.mk
|
||||
include src/main/iidxhook6/Module.mk
|
||||
include src/main/iidxhook7/Module.mk
|
||||
include src/main/iidxhook8/Module.mk
|
||||
@@ -154,6 +164,9 @@ include src/main/p3io/Module.mk
|
||||
include src/main/p3ioemu/Module.mk
|
||||
include src/main/p4iodrv/Module.mk
|
||||
include src/main/p4ioemu/Module.mk
|
||||
include src/main/popnhook-util/Module.mk
|
||||
include src/main/popnhook1/Module.mk
|
||||
include src/main/popnio/Module.mk
|
||||
include src/main/pcbidgen/Module.mk
|
||||
include src/main/sdvxhook/Module.mk
|
||||
include src/main/sdvxhook2-cn/Module.mk
|
||||
@@ -331,6 +344,22 @@ $(zipdir)/iidx-20.zip: \
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/iidx-20-cn.zip: \
|
||||
build/bin/avs2_1304-32/iidxhook5-cn.dll \
|
||||
build/bin/indep-32/config.exe \
|
||||
build/bin/indep-32/eamio.dll \
|
||||
build/bin/indep-32/geninput.dll \
|
||||
build/bin/indep-32/iidxio.dll \
|
||||
build/bin/indep-32/vefxio.dll \
|
||||
build/bin/indep-32/inject.exe \
|
||||
dist/iidx/config.bat \
|
||||
dist/iidx/gamestart-20-cn.bat \
|
||||
dist/iidx/iidxhook-20-cn.conf \
|
||||
dist/iidx/vefx.txt \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/iidx-21-to-24.zip: \
|
||||
build/bin/avs2_1601-32/iidxhook7.dll \
|
||||
build/bin/avs2_1601-32/launcher.exe \
|
||||
@@ -685,6 +714,26 @@ $(zipdir)/bst.zip: \
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/popn-15-to-18.zip: \
|
||||
build/bin/avs2_803-32/popnhook1.dll \
|
||||
build/bin/indep-32/config.exe \
|
||||
build/bin/indep-32/inject.exe \
|
||||
build/bin/indep-32/geninput.dll \
|
||||
build/bin/indep-32/eamio.dll \
|
||||
build/bin/indep-32/popnio.dll \
|
||||
build/bin/indep-32/ezusb2-popn-shim.dll \
|
||||
dist/popn/gamestart-15.bat \
|
||||
dist/popn/gamestart-16.bat \
|
||||
dist/popn/gamestart-17.bat \
|
||||
dist/popn/gamestart-18.bat \
|
||||
dist/popn/popnhook-15.conf \
|
||||
dist/popn/popnhook-16.conf \
|
||||
dist/popn/popnhook-17.conf \
|
||||
dist/popn/popnhook-18.conf \
|
||||
| $(zipdir)/
|
||||
$(V)echo ... $@
|
||||
$(V)zip -j $@ $^
|
||||
|
||||
$(zipdir)/doc.zip: \
|
||||
doc/ \
|
||||
| $(zipdir)/
|
||||
@@ -732,6 +781,7 @@ $(BUILDDIR)/bemanitools.zip: \
|
||||
$(zipdir)/iidx-18.zip \
|
||||
$(zipdir)/iidx-19.zip \
|
||||
$(zipdir)/iidx-20.zip \
|
||||
$(zipdir)/iidx-20-cn.zip \
|
||||
$(zipdir)/iidx-21-to-24.zip \
|
||||
$(zipdir)/iidx-25-to-26.zip \
|
||||
$(zipdir)/iidx-27-to-28.zip \
|
||||
@@ -744,6 +794,7 @@ $(BUILDDIR)/bemanitools.zip: \
|
||||
$(zipdir)/jb-05-to-07.zip \
|
||||
$(zipdir)/jb-08.zip \
|
||||
$(zipdir)/jb-hwio.zip \
|
||||
$(zipdir)/popn-15-to-18.zip \
|
||||
$(zipdir)/sdvx-01-to-04.zip \
|
||||
$(zipdir)/sdvx-05-to-06.zip \
|
||||
$(zipdir)/sdvx-05-cn.zip \
|
||||
|
||||
10
README.md
10
README.md
@@ -1,7 +1,7 @@
|
||||
# Bemanitools 5
|
||||
[](https://dev.s-ul.net/djhackers/bemanitools/commits/master)
|
||||
|
||||
Version: 5.40
|
||||
Version: 5.41
|
||||
|
||||
[Release history](CHANGELOG.md)
|
||||
|
||||
@@ -51,6 +51,7 @@ The following games are supported with their corresponding hook-libraries.
|
||||
* Beatmania IIDX 17 SIRIUS (`iidx-14-to-17.zip`): [iidxhook3](doc/iidxhook/iidxhook3.md)
|
||||
* Beatmania IIDX 18 Resort Anthem (`iidx-18.zip`): [iidxhook4](doc/iidxhook/iidxhook4.md)
|
||||
* Beatmania IIDX 19 Lincle (`iidx-19.zip`): [iidxhook5](doc/iidxhook/iidxhook5.md)
|
||||
* Beatmania IIDX tricoro CN (狂热节拍 IIDX 2) (`iidx-20-cn.zip`): [iidxhook5-cn](doc/iidxhook/iidxhook5-cn.md)
|
||||
* Beatmania IIDX 20 Tricoro (`iidx-20.zip`): [iidxhook6](doc/iidxhook/iidxhook6.md)
|
||||
* Beatmania IIDX 21 SPADA (`iidx-21-to-24.zip`): [iidxhook7](doc/iidxhook/iidxhook7.md)
|
||||
* Beatmania IIDX 22 PENDUAL (`iidx-21-to-24.zip`): [iidxhook7](doc/iidxhook/iidxhook7.md)
|
||||
@@ -70,6 +71,11 @@ The following games are supported with their corresponding hook-libraries.
|
||||
* jubeat qubell (`jb-05-to-07.zip`): [jbhook3](doc/jbhook/jbhook3.md)
|
||||
* jubeat clan (`jb-08.zip`): [jbhook3](doc/jbhook/jbhook3.md)
|
||||
* jubeat festo (`jb-08.zip`): [jbhook3](doc/jbhook/jbhook3.md)
|
||||
* [pop'n music](doc/popnhook/README.md)
|
||||
* pop'n music 15 ADVENTURE (`popn-15-to-18.zip`) using [popnhook1](doc/popnhook/popnhook1.md)
|
||||
* pop'n music 16 PARTY♪ (`popn-15-to-18.zip`) using [popnhook1](doc/popnhook/popnhook1.md)
|
||||
* pop'n music 17 THE MOVIE (`popn-15-to-18.zip`) using [popnhook1](doc/popnhook/popnhook1.md)
|
||||
* pop'n music 18 せんごく列伝 (`popn-15-to-18.zip`) using [popnhook1](doc/popnhook/popnhook1.md)
|
||||
* SOUND VOLTEX
|
||||
* SOUND VOLTEX BOOTH (`sdvx-01-to-04.zip`): sdvxhook
|
||||
* SOUND VOLTEX II -infinite infection- (`sdvx-01-to-04.zip`): sdvxhook
|
||||
@@ -91,7 +97,7 @@ change in the future. Many games also run on very recent Windows 10 builds but b
|
||||
with Windows updates breaking legacy software.
|
||||
|
||||
## Distribution contents
|
||||
Check the [list of supported games](#list-of-supported-games) to grab the right files for your game. BT5 also includes
|
||||
Check the [list of supported games](#supported-games) to grab the right files for your game. BT5 also includes
|
||||
a *tools* subpackage (tools.zip) as well as the full source code (src.zip).
|
||||
|
||||
You will find *.md files in various sub-packages that give you further instructions for setup, usage, error information
|
||||
|
||||
14
dist/iidx/gamestart-20-cn.bat
vendored
Normal file
14
dist/iidx/gamestart-20-cn.bat
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
|
||||
cd /d %~dp0
|
||||
|
||||
if not exist d mkdir d
|
||||
if not exist e mkdir e
|
||||
if not exist f mkdir f
|
||||
|
||||
if not exist e\avs_conf mkdir e\avs_conf
|
||||
if not exist e\avs_conf\CONF mkdir e\avs_conf\CONF
|
||||
if not exist e\avs_conf\CONF\NVRAM mkdir e\avs_conf\CONF\NVRAM
|
||||
if not exist e\avs_conf\CONF\RAW mkdir e\avs_conf\CONF\RAW
|
||||
|
||||
inject iidxhook5-cn.dll bm2dx.exe -D --config iidxhook-20-cn.conf %*
|
||||
44
dist/iidx/iidxhook-20-cn.conf
vendored
Normal file
44
dist/iidx/iidxhook-20-cn.conf
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# PCBID
|
||||
eamuse.pcbid=0101020304050607086F
|
||||
|
||||
# Fix stretched BG videos on newer GPUs. Might appear on Red and newer
|
||||
gfx.bgvideo_uv_fix=false
|
||||
|
||||
# Run the game in a framed window (requires windowed option)
|
||||
gfx.framed=false
|
||||
|
||||
# Software limit the frame rate of the rendering loop in hz, e.g. 60 or 59.95 (0.0 = no software limit)
|
||||
gfx.frame_rate_limit=0.0
|
||||
|
||||
# Patch the GPU device ID detection (leave empty to disable), format XXXX:YYYY, two 4 digit hex numbers (vid:pid). Examples: 1002:7146 (RV515, Radeon X1300), 1002:95C5 (RV620 LE, Radeon HD3450)
|
||||
gfx.pci_id=1002:7146
|
||||
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Windowed width, 0 for default size
|
||||
gfx.window_width=0
|
||||
|
||||
# Windowed height, 0 for default size
|
||||
gfx.window_height=0
|
||||
|
||||
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
|
||||
gfx.scale_back_buffer_width=0
|
||||
|
||||
# Up-/downscale the back buffer's height. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding width parameter.
|
||||
gfx.scale_back_buffer_height=0
|
||||
|
||||
# Filter type to use for up-/downscaling the back buffer. Only used if scaling feature was enabled by setting the scaling width and height parameters. Available types: none, linear, point (refer to D3DTEXTUREFILTERTYPE for explanation).
|
||||
gfx.scale_back_buffer_filter=none
|
||||
|
||||
# Forced refresh rate, -1 to not force any (try 59 or 60 if monitor check fails to lock on high refresh rate monitors)
|
||||
gfx.forced_refresh_rate=-1
|
||||
|
||||
# D3D9 device adapter (monitor), -1 to use default, 0, 1, 2 etc. to use specified adapter
|
||||
gfx.device_adapter=-1
|
||||
|
||||
# Disable ezusb IO emulation and enable usage of real ezusb1/2 IO hardware
|
||||
io.disable_io_emu=false
|
||||
|
||||
# Security black plug mcode id string (e.g. GQC02JAA).
|
||||
sec.black_plug_mcode=GKJDZCAA
|
||||
16
dist/popn/gamestart-15.bat
vendored
Normal file
16
dist/popn/gamestart-15.bat
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
|
||||
cd /d %~dp0
|
||||
|
||||
if not exist e\bookkeeping mkdir e\bookkeeping
|
||||
if not exist e\CONF\NVRAM mkdir e\CONF\NVRAM
|
||||
if not exist e\CONF\NVRAM\0 mkdir e\CONF\NVRAM\0
|
||||
if not exist e\CONF\NVRAM\1 mkdir e\CONF\NVRAM\1
|
||||
if not exist e\CONF\NVRAM\2 mkdir e\CONF\NVRAM\2
|
||||
if not exist e\CONF\NVRAM\3 mkdir e\CONF\NVRAM\3
|
||||
if not exist e\CONF\RAW mkdir e\CONF\RAW
|
||||
if not exist e\settings mkdir e\settings
|
||||
if not exist e\UP mkdir e\UP
|
||||
|
||||
inject popnhook1.dll ezusb.dll=ezusb2-popn-shim.dll popn15.exe --config popnhook-15.conf %*
|
||||
|
||||
16
dist/popn/gamestart-16.bat
vendored
Normal file
16
dist/popn/gamestart-16.bat
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
|
||||
cd /d %~dp0
|
||||
|
||||
if not exist e\bookkeeping mkdir e\bookkeeping
|
||||
if not exist e\CONF\NVRAM mkdir e\CONF\NVRAM
|
||||
if not exist e\CONF\NVRAM\0 mkdir e\CONF\NVRAM\0
|
||||
if not exist e\CONF\NVRAM\1 mkdir e\CONF\NVRAM\1
|
||||
if not exist e\CONF\NVRAM\2 mkdir e\CONF\NVRAM\2
|
||||
if not exist e\CONF\NVRAM\3 mkdir e\CONF\NVRAM\3
|
||||
if not exist e\CONF\RAW mkdir e\CONF\RAW
|
||||
if not exist e\settings mkdir e\settings
|
||||
if not exist e\UP mkdir e\UP
|
||||
|
||||
inject popnhook1.dll ezusb.dll=ezusb2-popn-shim.dll popn16.exe --config popnhook-16.conf %*
|
||||
|
||||
16
dist/popn/gamestart-17.bat
vendored
Normal file
16
dist/popn/gamestart-17.bat
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
|
||||
cd /d %~dp0
|
||||
|
||||
if not exist e\bookkeeping mkdir e\bookkeeping
|
||||
if not exist e\CONF\NVRAM mkdir e\CONF\NVRAM
|
||||
if not exist e\CONF\NVRAM\0 mkdir e\CONF\NVRAM\0
|
||||
if not exist e\CONF\NVRAM\1 mkdir e\CONF\NVRAM\1
|
||||
if not exist e\CONF\NVRAM\2 mkdir e\CONF\NVRAM\2
|
||||
if not exist e\CONF\NVRAM\3 mkdir e\CONF\NVRAM\3
|
||||
if not exist e\CONF\RAW mkdir e\CONF\RAW
|
||||
if not exist e\settings mkdir e\settings
|
||||
if not exist e\UP mkdir e\UP
|
||||
|
||||
inject popnhook1.dll ezusb.dll=ezusb2-popn-shim.dll popn17.exe --config popnhook-17.conf %*
|
||||
|
||||
16
dist/popn/gamestart-18.bat
vendored
Normal file
16
dist/popn/gamestart-18.bat
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
|
||||
cd /d %~dp0
|
||||
|
||||
if not exist e\bookkeeping mkdir e\bookkeeping
|
||||
if not exist e\CONF\NVRAM mkdir e\CONF\NVRAM
|
||||
if not exist e\CONF\NVRAM\0 mkdir e\CONF\NVRAM\0
|
||||
if not exist e\CONF\NVRAM\1 mkdir e\CONF\NVRAM\1
|
||||
if not exist e\CONF\NVRAM\2 mkdir e\CONF\NVRAM\2
|
||||
if not exist e\CONF\NVRAM\3 mkdir e\CONF\NVRAM\3
|
||||
if not exist e\CONF\RAW mkdir e\CONF\RAW
|
||||
if not exist e\settings mkdir e\settings
|
||||
if not exist e\UP mkdir e\UP
|
||||
|
||||
inject popnhook1.dll ezusb.dll=ezusb2-popn-shim.dll popn18.exe --config popnhook-18.conf %*
|
||||
|
||||
23
dist/popn/popnhook-15.conf
vendored
Normal file
23
dist/popn/popnhook-15.conf
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80.
|
||||
eamuse.server=localhost:80
|
||||
|
||||
# PCBID
|
||||
eamuse.pcbid=0101020304050607086F
|
||||
|
||||
# EAMID
|
||||
eamuse.eamid=0101020304050607086F
|
||||
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Run the game in a framed window (requires windowed option)
|
||||
gfx.framed=false
|
||||
|
||||
# Windowed width, 0 for default size
|
||||
gfx.window_width=0
|
||||
|
||||
# Windowed height, 0 for default size
|
||||
gfx.window_height=0
|
||||
|
||||
# Security black plug mcode id string (e.g. GQC02JAA).
|
||||
sec.black_plug_mcode=GQG15JAA
|
||||
23
dist/popn/popnhook-16.conf
vendored
Normal file
23
dist/popn/popnhook-16.conf
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80.
|
||||
eamuse.server=localhost:80
|
||||
|
||||
# PCBID
|
||||
eamuse.pcbid=0101020304050607086F
|
||||
|
||||
# EAMID
|
||||
eamuse.eamid=0101020304050607086F
|
||||
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Run the game in a framed window (requires windowed option)
|
||||
gfx.framed=false
|
||||
|
||||
# Windowed width, 0 for default size
|
||||
gfx.window_width=0
|
||||
|
||||
# Windowed height, 0 for default size
|
||||
gfx.window_height=0
|
||||
|
||||
# Security black plug mcode id string (e.g. GQC02JAA).
|
||||
sec.black_plug_mcode=GQH16JAA
|
||||
23
dist/popn/popnhook-17.conf
vendored
Normal file
23
dist/popn/popnhook-17.conf
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80.
|
||||
eamuse.server=localhost:80
|
||||
|
||||
# PCBID
|
||||
eamuse.pcbid=0101020304050607086F
|
||||
|
||||
# EAMID
|
||||
eamuse.eamid=0101020304050607086F
|
||||
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Run the game in a framed window (requires windowed option)
|
||||
gfx.framed=false
|
||||
|
||||
# Windowed width, 0 for default size
|
||||
gfx.window_width=0
|
||||
|
||||
# Windowed height, 0 for default size
|
||||
gfx.window_height=0
|
||||
|
||||
# Security black plug mcode id string (e.g. GQC02JAA).
|
||||
sec.black_plug_mcode=GQI17JAA
|
||||
23
dist/popn/popnhook-18.conf
vendored
Normal file
23
dist/popn/popnhook-18.conf
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80.
|
||||
eamuse.server=localhost:80
|
||||
|
||||
# PCBID
|
||||
eamuse.pcbid=0101020304050607086F
|
||||
|
||||
# EAMID
|
||||
eamuse.eamid=0101020304050607086F
|
||||
|
||||
# Run the game windowed
|
||||
gfx.windowed=false
|
||||
|
||||
# Run the game in a framed window (requires windowed option)
|
||||
gfx.framed=false
|
||||
|
||||
# Windowed width, 0 for default size
|
||||
gfx.window_width=0
|
||||
|
||||
# Windowed height, 0 for default size
|
||||
gfx.window_height=0
|
||||
|
||||
# Security black plug mcode id string (e.g. GQC02JAA).
|
||||
sec.black_plug_mcode=GCJ39JAA
|
||||
@@ -4,6 +4,9 @@ This folder contains various types of documentation.
|
||||
|
||||
Table of contents:
|
||||
|
||||
* Game
|
||||
* [Error codes](game-error-codes.md): List of bemani game specific error codes that you might
|
||||
encounter during boot or gameplay with troubleshooting information
|
||||
* Key tools
|
||||
* [Inject](inject.md): Readme for one of BT5's key applications, `inject.exe`
|
||||
* [Launcher](launcher.md): Readme for another one of BT5's key applications, `launcher.exe`
|
||||
@@ -12,6 +15,7 @@ Table of contents:
|
||||
* [ddrhook](ddrhook/README.md): Documentation relevant to `ddrhook` implementations
|
||||
* [iidxhook](iidxhook/README.md): Documentation relevant to `iidxhook` implementations
|
||||
* [jbhook](jbhook/README.md): Documentation relevant to `jbhook` implementations
|
||||
* [popnhook](popnhook/README.md): Documentation relevant to `popnhook` implementations
|
||||
* [sdvxhook](sdvxhook/README.md): Documentation relevant to `sdvxhook` implementations
|
||||
* Development
|
||||
* [API](api.md): Available APIs for BT5 and instructions how to use them
|
||||
|
||||
@@ -12,7 +12,7 @@ If you want to write an implementation for your own custom piece of hardware, ch
|
||||
sub-folder) in the source code (src.zip).
|
||||
|
||||
## Implementations
|
||||
The following implementations are already shipped with BT5.
|
||||
The following implementations are already shipped with BT5.
|
||||
|
||||
* BeatStream
|
||||
* bstio.dll (default): Keyboard, joystick and mouse input
|
||||
@@ -27,13 +27,15 @@ The following implementations are already shipped with BT5.
|
||||
* [iidxio-ezusb2.dll](iidxhook/iidxio-ezusb2.md): Ezusb FX2 (IO2) driver
|
||||
* jubeat
|
||||
* jbio.dll (default): Keyboard, joystick and mouse input
|
||||
* pop'n music
|
||||
* popnio.dll (default): Keyboard, joystick and mouse input
|
||||
* SOUND VOLTEX
|
||||
* sdvxio.dll (default): Keyboard, joystick and mouse input
|
||||
* [sdvxio-bio2.dll](sdvxhook/sdvxio-bio2.md): BIO2 driver
|
||||
* [sdvxio-kfca.dll](sdvxhook/sdvxio-kfca.md): KFCA IO board driver
|
||||
|
||||
Eamuse hardware support is implemented separately:
|
||||
* eamio.dll (default): Keyboard and joystick input
|
||||
* eamio.dll (default): Keyboard and joystick input
|
||||
|
||||
## Development notes
|
||||
A DEF file for geninput.dll is included. To convert the DEF into an import library suitable for use with Visual C++, run
|
||||
|
||||
@@ -51,7 +51,7 @@ Modules that make use of this:
|
||||
* ezusb2-emu/device
|
||||
* acioemu/emu
|
||||
|
||||
## Bemanitools's hook libraries, let's glue everything together
|
||||
## Bemanitools's hook libraries, let's glue everything together
|
||||
Bemanitools dlls to be injected into target game processes are refered to as "hook dlls" and come in different flavours
|
||||
targetting different games and often different versions of the same game (series), for example:
|
||||
* ddrhook: Hook dll for Dance Dance Revolution games
|
||||
@@ -69,13 +69,13 @@ TODO
|
||||
|
||||
### iidxhook
|
||||
IIDX went through so many hard- and software iterations, it's actually amazing that the development team(s) refactored
|
||||
and improved parts of the game and hardware with each iteration. However, when facing emulation and supporting
|
||||
and improved parts of the game and hardware with each iteration. However, when facing emulation and supporting
|
||||
compatibility to legacy OS platforms, it can't get any worse. On the bright side, IIDX helped shaping Bemanitools a lot
|
||||
and created a solid foundation other games can build on.
|
||||
|
||||
Because of that, we have 8 iidxhook implementations supporting sometimes different software features/fixes and
|
||||
hardware. The following sub-sub-sections list the most relevant aspects and modules to point out common and different
|
||||
higher level features.
|
||||
higher level features.
|
||||
|
||||
Essentially, the main module file of each iidxhook implementation just glues the APIs of the modules it requires
|
||||
together. An additional configuration layer allows users to tweak some of the features.
|
||||
@@ -88,7 +88,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
* Setupapi emulation
|
||||
* Full security emulation with SRAM and round plugs
|
||||
* Full serial emulation for magstripe card readers
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* d3d8 patching and extended features (superseded by d3d9 hook module + d3d8to9 wrapper)
|
||||
* clock patching
|
||||
* Font patching for Japanese chars
|
||||
@@ -99,7 +99,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
* Ezusb C02 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full security emulation with SRAM and round plugs
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, slotted readers
|
||||
* d3d8 patching and extended features (superseded by d3d9 hook module + d3d8to9 wrapper)
|
||||
* clock patching
|
||||
@@ -111,7 +111,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
* Ezusb IO2 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full security emulation with SRAM and round plugs
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, slotted readers
|
||||
* d3d9 patching and extended features
|
||||
* Font patching for Japanese chars
|
||||
@@ -121,7 +121,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
#### iidxhook4 (18)
|
||||
* Ezusb IO2 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, slotted readers
|
||||
* d3d9 patching and extended features
|
||||
* Font patching for Japanese chars
|
||||
@@ -130,7 +130,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
#### iidxhook5 (19)
|
||||
* Ezusb IO2 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, wave pass readers
|
||||
* d3d9 patching and extended features
|
||||
* Font patching for Japanese chars
|
||||
@@ -139,7 +139,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
#### iidxhook6 (20)
|
||||
* Ezusb IO2 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, wave pass readers
|
||||
* d3d9 patching and extended features
|
||||
* Font patching for Japanese chars
|
||||
@@ -147,7 +147,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
#### iidxhook7 (21-24)
|
||||
* Ezusb IO2 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, wave pass readers
|
||||
* d3d9 patching and extended features
|
||||
* Font patching for Japanese chars
|
||||
@@ -155,7 +155,7 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
#### iidxhook8 (25-26)
|
||||
* ACIO BIO2 I/O emulation
|
||||
* Setupapi emulation
|
||||
* Full game essential I/O emulation
|
||||
* Full game essential I/O emulation
|
||||
* ACIO ICCA card reader emulation, wave pass readers
|
||||
* d3d9 patching and extended features
|
||||
* Font patching for Japanese chars
|
||||
@@ -163,6 +163,9 @@ TODO go into some more detail about some differences in the hook modules, e.g. 1
|
||||
### jbhook
|
||||
TODO
|
||||
|
||||
### popnhook
|
||||
TODO
|
||||
|
||||
### sdvxhook
|
||||
TODO
|
||||
|
||||
|
||||
781
doc/game-error-codes.md
Normal file
781
doc/game-error-codes.md
Normal file
@@ -0,0 +1,781 @@
|
||||
# Bemani Game Error Codes
|
||||
|
||||
This document collects the various error codes that are know across the many games including some
|
||||
information what can be done.
|
||||
|
||||
This information is not part of bemanitools but useful to many users using it to run the games. We
|
||||
saw users encountering these errors not knowing what they mean. Therefore, we include these errors
|
||||
in the repository to provide an accessible source of information regarding them.
|
||||
|
||||
Important: The error codes are not consistent throughout the many years of game series and versions.
|
||||
|
||||
It is adviced to read the error information carefully (use Google Translate App with your phone's
|
||||
camera) and check the following sections. It would be great to get feedback if you see information
|
||||
missing or specific games and versions not matching to increase the value of the list.
|
||||
|
||||
## 5-0000 series errors
|
||||
|
||||
### 5-0000-0000
|
||||
|
||||
#### Description
|
||||
|
||||
A generic critical error.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How to fix
|
||||
|
||||
* Make sure your data is not set to read only, especially the dev folder.
|
||||
* Disable all network adapters other than the one used to connect to the Internet.
|
||||
* Check for hidden network adapters in Device Manager.
|
||||
|
||||
## 5-1500 series errors
|
||||
|
||||
### 5-1500-0000
|
||||
|
||||
#### Description
|
||||
|
||||
IO ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* Pop'n Music 15
|
||||
|
||||
#### How to fix
|
||||
|
||||
No information available.
|
||||
|
||||
### 5-1500-0002
|
||||
|
||||
#### Description
|
||||
|
||||
SOUND DATA CREATE ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How to fix
|
||||
|
||||
* Check the integrity of the data you have, i.e. some files might be corrupted
|
||||
* Check your physical drive. Is it failing?
|
||||
|
||||
## 5-1501 series errors
|
||||
|
||||
### 5-1501-0000
|
||||
|
||||
#### Description
|
||||
|
||||
IO BOARD ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How to fix
|
||||
|
||||
* Recopy Bemanitools.
|
||||
* For Reflec Beat, make sure you are not missing device.dll. (This seems to apply to some older
|
||||
version of bemanitools)
|
||||
|
||||
## 5-1502 series errors
|
||||
|
||||
### 5-1502-0000
|
||||
|
||||
#### Description
|
||||
|
||||
BACKUP CHECK ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* Pop'n'Music 21 Sunny Park
|
||||
|
||||
#### How to fix
|
||||
|
||||
* Give access to gamestart.bat and launcher.exe from Windows Firewall if enabled.
|
||||
* Make sure no antivirus software firewall is blocking access to those files.
|
||||
* Start gamestart.bat as Administrator.
|
||||
|
||||
### 5-1502-0000
|
||||
|
||||
#### Description
|
||||
|
||||
HDD READ ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How to fix
|
||||
|
||||
* Make sure `/dev/` isn't read-only.
|
||||
|
||||
### 5-1502-0002
|
||||
|
||||
#### Description
|
||||
|
||||
HDD READ ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* GFDM V4
|
||||
|
||||
#### How to fix
|
||||
|
||||
Unknown
|
||||
|
||||
## 5-1503 series errors
|
||||
|
||||
### 5-1503-0000
|
||||
|
||||
#### Description
|
||||
|
||||
USB I/O ERROR
|
||||
|
||||
##### FPGA WRITE ERROR
|
||||
|
||||
Writing the FPGA firmware fails. Can have various causes depending on your setup.
|
||||
|
||||
##### FW TRNS-OUT
|
||||
|
||||
This typically happens if it takes too long to upload the base firmware to the USB IO. A potential
|
||||
root-cause can be bad timing since the game uses a bad combination of software sleeps and fixed
|
||||
timeouts making this code prone to fail.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* IIDX
|
||||
|
||||
#### How to fix
|
||||
|
||||
#### FPGA WRITE ERROR
|
||||
|
||||
* Restart the game
|
||||
* Re-copy bemanitools
|
||||
|
||||
#### FW TRNS-OUT
|
||||
|
||||
* Restart the game
|
||||
* Re-copy bemanitools
|
||||
* Running the process on high priority and with admin rights
|
||||
* If you attached a debugger, that might have messed with the timing and caused this. Try a
|
||||
different debugger or attach it later in the boot process
|
||||
|
||||
### 5-1503-0001
|
||||
|
||||
#### Description
|
||||
|
||||
DATA ERROR
|
||||
|
||||
"Could not read the file normally. There is a likelihood the file is damaged."
|
||||
|
||||
This error occurs when a file is either missing or corrupt.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How to fix
|
||||
|
||||
* Check the integrity of the data you have, i.e. some files might be corrupted
|
||||
* If the data came in an archive format, try extracting it again with another application.
|
||||
* Make sure your game is up to date with the current data available.
|
||||
* Check your physical drive. Is it failing?
|
||||
|
||||
### 5-1503-0004
|
||||
|
||||
#### Description
|
||||
|
||||
USBIO ERROR (NO ANSWER...)
|
||||
|
||||
This error occurs when the game does not receive a heartbeat from the IO board. On legitimate
|
||||
hardware, this error is usually caused by the IO board resetting during play. The issue is rarely
|
||||
fixed by simply restarting the game and will require a full power cycle.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Real hardware:
|
||||
|
||||
* Check the USB cable between the PC and the IO board is okay.
|
||||
* Make sure the IO board is getting enough of a clean supply of power.
|
||||
|
||||
Bemanitools:
|
||||
|
||||
* Don't attempt to put your computer to sleep while playing rhythm games.
|
||||
* Change launcher.exe process priority to High when starting the game.
|
||||
|
||||
### 5-1503-0006
|
||||
|
||||
#### Description
|
||||
|
||||
CARD DEVICE ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Recopy Bemanitools.
|
||||
|
||||
### 5-1503-0007
|
||||
|
||||
#### Description
|
||||
|
||||
USBIO ERROR (FM DL-ERR)
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Run the game using gamestart.bat, don't just drag and drop the game dll onto launcher.exe
|
||||
|
||||
### 5-1503-0008
|
||||
|
||||
#### Description
|
||||
|
||||
FPGA Write error
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* IIDX Tricoro
|
||||
|
||||
Seen in Tricoro Omnimix RC1.
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Unknown
|
||||
|
||||
### 5-1503-9000
|
||||
|
||||
### Description
|
||||
|
||||
PCB ERROR (PCB is unusual.)
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Make sure your AC(real)IO board is on the correct COM port.
|
||||
|
||||
## 5-1504 series errors
|
||||
|
||||
### 5-1504-0000
|
||||
|
||||
#### Description
|
||||
|
||||
IC CARD READER ERROR
|
||||
|
||||
Something is wrong with your e-amusement card readers (usually a timeout due to them not existing).
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Real hardware:
|
||||
|
||||
* Make sure your readers are connected and powered on.
|
||||
* Check your serial cables are good.
|
||||
|
||||
### 5-1504-0003
|
||||
|
||||
### Description
|
||||
|
||||
N/A
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
N/A
|
||||
|
||||
### 5-1504-0004
|
||||
|
||||
### Description
|
||||
|
||||
SDLOAD TIMEOUT or SOUND LOAD TIMEOUT
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
N/A
|
||||
|
||||
## 5-1505 series errors
|
||||
|
||||
### 5-1505-0000
|
||||
|
||||
#### Description
|
||||
|
||||
HDD Data Error(BPM Notes)
|
||||
|
||||
For Jubeat Ripples, getting this error the first time you boot is normal. After getting this error,
|
||||
the game may take 1-3 minutes longer to boot as it regenerates backup data.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* Jubeat Ripples
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Check the integrity of the data you have, i.e. some files might be corrupted
|
||||
* If the data came in an archive format, try extracting it again with another application.
|
||||
* Check your physical drive. Is it failing?
|
||||
|
||||
### 5-1505-0001
|
||||
|
||||
#### Description
|
||||
|
||||
HDD Data Error(Music Data)
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Check the integrity of the data you have, i.e. some files might be corrupted
|
||||
* If the data came in an archive format, try extracting it again with another application.
|
||||
* Check your physical drive. Is it failing?
|
||||
|
||||
### 5-1505-0002
|
||||
|
||||
#### Description
|
||||
|
||||
Coin Error
|
||||
|
||||
This error occurs when the coin line (the input triggered when a coin is inserted) is held closed
|
||||
for too long.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
##### Real hardware
|
||||
|
||||
* There may be a coin stuck, check.
|
||||
* The coin mechanism may be stuck, check.
|
||||
* Don't hold down the coin line so long.
|
||||
|
||||
### 5-1505-0006
|
||||
|
||||
#### Description
|
||||
|
||||
HDD DATA ERROR(MOUNT IMAGEFS)
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Check the integrity of the data you have, i.e. some files might be corrupted
|
||||
* If the data came in an archive format, try extracting it again with another application.
|
||||
* Check your physical drive. Is it failing?
|
||||
|
||||
### 5-1505-0025
|
||||
|
||||
#### Description
|
||||
|
||||
N/A
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* Jubeat Saucer Fullfill
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Disable excess network adapters
|
||||
|
||||
## 5-1506 series errors
|
||||
|
||||
### 5-1506-0000
|
||||
|
||||
#### Description
|
||||
|
||||
##### ACIO ERROR (ERR_INIT_LINE)
|
||||
|
||||
##### BACKUP DATA ERROR
|
||||
|
||||
The backup data is corrupted. Press the test button to re-initialize it.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* IIDX 15 (BACKUP DATA ERROR)
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
##### ACIO ERROR
|
||||
|
||||
If you're using ACrealIO, cut the reset trace on your Arduino.
|
||||
|
||||
##### BACKUP DATA ERROR
|
||||
|
||||
Follow the instructions of the error message. You will have to re-set certain settings like clock
|
||||
settings in the operator menu to complete initialization.
|
||||
|
||||
### 5-1506-0001
|
||||
|
||||
#### Description
|
||||
|
||||
SHOP NAME ERROR
|
||||
|
||||
This error may happen before the monitor check on IIDX.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* IIDX (version?)
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Press the service button and set the shop name in "NETWORK OPTIONS".
|
||||
|
||||
### 5-1506-1001
|
||||
|
||||
#### Description
|
||||
|
||||
CLOCK ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* "Set" and save the clock date and time in the test menu
|
||||
* Recopy Bemanitools
|
||||
|
||||
## 5-1507 series errors
|
||||
|
||||
### 5-1507-0000
|
||||
|
||||
#### Description
|
||||
|
||||
SECURITY ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Make sure your ea3-config.xml file contains valid values on the following lines:
|
||||
|
||||
```xml
|
||||
<dest __type="str">...</dest>
|
||||
```
|
||||
|
||||
Should almost always be `J`. Certain games will support `K` (Korea) or `A` (Asia) but there is
|
||||
rarely a reason to use it. DDR 2014 and forward will support `U`. DanEvo will support (I believe)
|
||||
`C`.
|
||||
|
||||
```xml
|
||||
<spec __type="str">...</spec>
|
||||
```
|
||||
|
||||
Should almost always be `A`. DDR will support `B` for non-HD monitors.
|
||||
|
||||
```xml
|
||||
<rev __type="str">...</rev>
|
||||
```
|
||||
|
||||
Should always be `A`.
|
||||
|
||||
## 5-1508 series errors
|
||||
|
||||
### 5-1508-0000
|
||||
|
||||
#### Description
|
||||
|
||||
LAMP CHECK ERROR
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* Pop'n Music 20 Fantasia
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
N/A
|
||||
|
||||
## 5-1509 series errors
|
||||
|
||||
### 5-1509-0000
|
||||
|
||||
#### Description
|
||||
|
||||
REBOOT THE MACHINE
|
||||
|
||||
The original message in Japanese: 電源を再投入して下さい
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* Pop'n Music 22 Lapistoria
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Restart entire machine if on cabinet, or close the game (ALT+F4/ALT+TAB and then close through
|
||||
taskbar) and re-run the launcher/gamestart file
|
||||
|
||||
## 5-2000 series errors (Network errors)
|
||||
|
||||
### 5-2000-0000
|
||||
|
||||
#### Description
|
||||
|
||||
Router error.
|
||||
|
||||
Something's not okay with the connection between the game and your router. This can either be a
|
||||
(W)LAN error, or something within your computer settings (firewall, network adapter, etc.)
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Restart your game.
|
||||
* Check if your computer is connected to the Internet at all.
|
||||
* Make sure the services URL is correct.
|
||||
* Disable all network adapters other than the one used to connect to the Internet. Alternatively,
|
||||
setting that adapter to have the highest affinity also works.
|
||||
* If none of the above work, reinstall a newer or older version of your network drivers.
|
||||
|
||||
### 5-2002-0000
|
||||
|
||||
#### Description
|
||||
|
||||
speculation: general malformed ea3-config.xml file or server communication error
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Make sure you're editing the right file for network configuration settings.
|
||||
|
||||
### 5-2002-0916
|
||||
|
||||
#### Description
|
||||
|
||||
Cannot communicate with the server.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
N/A
|
||||
|
||||
### 5-2002-1013
|
||||
|
||||
#### Description
|
||||
|
||||
NETWORK ERROR
|
||||
|
||||
Cannot communicate with server.
|
||||
|
||||
Ensure that your internet connection is working and that your router is turned on.
|
||||
|
||||
Ensure that your machine is connected to your router.
|
||||
|
||||
Press the service button to start the game.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
* IIDX, probably all known versions
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
The original message is already telling you what is going on:
|
||||
|
||||
* Check if your machine/pc has an internet connection
|
||||
* Check your firewall settings
|
||||
* Check that the server address is configured and correct in `iidxhook.conf` (old games) or
|
||||
`ea3-config.xml`
|
||||
* You can disable the network in the operator menu to just boot the game first. Note that this is
|
||||
not possible on any versions starting IIDX 20 (tricoro).
|
||||
|
||||
### 5-2002-2301
|
||||
|
||||
#### Description
|
||||
|
||||
Cannot communicate with the server.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Your ea3 services URL is probably incorrect.
|
||||
|
||||
### 5-2000-2402
|
||||
|
||||
#### Description
|
||||
|
||||
No PCBID. You have no PCBID.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Add a valid PCBID to `ea3-config.xml`.
|
||||
|
||||
### 5-2002-0910
|
||||
|
||||
#### Description
|
||||
|
||||
Server Error. The game cannot communicate with the server.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Make sure the services URL is correct.
|
||||
|
||||
### 5-2002-2403
|
||||
|
||||
#### Description
|
||||
|
||||
Unauthorized. The server is rejecting your PCBID.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Check that there is a valid PCBID in ea3-config.xml.
|
||||
|
||||
### 5-2002-2400
|
||||
|
||||
#### Description
|
||||
|
||||
Bad Request. Syntax was entered improperly and the server does not understand it.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Check your services URL and make sure it is entered correctly (e.g. "http:" instead of "https:")
|
||||
|
||||
### 5-2002-2404
|
||||
|
||||
#### Description
|
||||
|
||||
Not found. The server can't find the URL that the game has requested, this is usually because the
|
||||
game is attempting to connect to an incorrect endpoint.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
* Check your services URL in `ea3-config.xml`. Make sure to remove any slash at the end of the URL
|
||||
and check for https/http.
|
||||
* If you are running Spada, ensure to use a service URL that supports that older game (check with
|
||||
your private server provider)
|
||||
* If you are running Tune Street, ensure to use a service URL that supports that older game (check
|
||||
with your private server provider)
|
||||
|
||||
### 5-2003-2404
|
||||
|
||||
#### Description
|
||||
|
||||
Malformed `<network>` section. The `<network>` section in your `ea3-config.xml` file is malformed
|
||||
in some way.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Ensure your `<network>` section follows the following format:
|
||||
|
||||
```xml
|
||||
<network>
|
||||
<timeout __type="u32">10000</timeout>
|
||||
<sz_xrpc_buf __type="u32">102400</sz_xrpc_buf>
|
||||
<ssl __type="bool">0</ssl>
|
||||
<services></services>
|
||||
<url_slash __type="bool">1</url_slash>
|
||||
</network>
|
||||
```
|
||||
|
||||
Note: Delete the line `<url_slash __type="bool">1</url_slash>` if you're connecting to Arcana
|
||||
|
||||
### 5-2002-2500
|
||||
|
||||
#### Description
|
||||
|
||||
??? (Logs say http status 500)
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
If you are playing Lincle, use the `/core/services` URL from Tricoro, not xrpc.
|
||||
|
||||
### 5-2003-2502
|
||||
|
||||
#### Description
|
||||
|
||||
Server Error. The game cannot communicate with the server.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Check if your `hosts` file has any DNS redirects to other private servers that might interfere
|
||||
with this
|
||||
|
||||
### 5-2016-0000
|
||||
|
||||
#### Description
|
||||
|
||||
"apsmanager" is a special eAM Participation system for Korean machines(XXX:K). This system
|
||||
is maybe not supported by private servers.
|
||||
|
||||
#### Known occurances
|
||||
|
||||
N/A
|
||||
|
||||
#### How do I fix it?
|
||||
|
||||
Make sure your `ea3-config.xml` has this line set to 0:
|
||||
|
||||
```xml
|
||||
<apsmanager __type="u8">0</apsmanager>
|
||||
```
|
||||
@@ -18,6 +18,7 @@ games:
|
||||
* [iidxhook3](iidxhook3.md): GOLD, DJ TROOPERS, EMPRESS, SIRIUS
|
||||
* [iidxhook4](iidxhook4.md): Resort Anthem
|
||||
* [iidxhook5](iidxhook5.md): Lincle
|
||||
* [iidxhook5-cn](iidxhook5-cn.md): tricoro CN (狂热节拍 IIDX 2)
|
||||
* [iidxhook6](iidxhook6.md): Tricoro
|
||||
* [iidxhook7](iidxhook7.md): SPADA, PENDUAL, copula, SINOBUZ
|
||||
* [iidxhook8](iidxhook8.md): CANNON BALLERS, Rootage
|
||||
|
||||
@@ -198,6 +198,13 @@ can't be refreshed very often to make it feel unresponsive. Solution:
|
||||
hit your 10key/numpad slower than normal
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears (RED, HAPPY SKY)
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
@@ -234,4 +241,4 @@ If one or multiple of these issues apply, use the built in scaling options by se
|
||||
*gfx.scale_back_buffer_width* and *gfx.scale_back_buffer_height* to a target resolution
|
||||
to scale to. Usually, you want to set this to the monitor's native resolution, e.g.
|
||||
1920x1080 for full HD. You can play around with a few different filters using
|
||||
*gfx.scale_back_buffer_filter* which impacts image quality/blurriness on upscaling.
|
||||
*gfx.scale_back_buffer_filter* which impacts image quality/blurriness on upscaling.
|
||||
@@ -154,6 +154,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
@@ -165,6 +165,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
@@ -175,6 +175,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
15
doc/iidxhook/iidxhook5-cn.md
Normal file
15
doc/iidxhook/iidxhook5-cn.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Game list
|
||||
|
||||
The following games are compatible with this version of iidxhook:
|
||||
* tricoro CN (狂热节拍 IIDX 2)
|
||||
|
||||
The games must be bootstrapped using [inject.exe](../inject.md).
|
||||
|
||||
# Remarks
|
||||
|
||||
tricoro CN (狂热节拍 IIDX 2):
|
||||
|
||||
* Game uses Lincle engine
|
||||
* Identifier being JDZ
|
||||
* Does not have NETWORK function
|
||||
* Game doesn't used card readers
|
||||
@@ -171,6 +171,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
@@ -177,6 +177,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
@@ -182,6 +182,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
@@ -185,6 +185,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
@@ -221,6 +221,13 @@ iidxhook can limit the frame rate for you (refer to help/config file)
|
||||
Use dxwnd and set settings like "Acquire admin caps" and "Fullscreen only"
|
||||
|
||||
## Background videos aren't working. When starting a song, windows is playing the error sound and a message box appears
|
||||
If you are running in window mode, you can see an error pop-up window with the title
|
||||
`DirectShow Texture3D Sample` and error message
|
||||
`Could not create source filter to graph! hr=<some number>`.
|
||||
|
||||
When running fullscreen, you only hear a windows error sound and the game appears to be frozen
|
||||
when trying to play a background video.
|
||||
|
||||
You are missing a codec to decode and play the videos. There are different
|
||||
methods available to get background videos working. Probably, the easiest
|
||||
solution: grab the CLVSD.ax file and go to Start -> Run -> regsvr32 clvsd.ax
|
||||
|
||||
48
doc/popnhook/README.md
Normal file
48
doc/popnhook/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# popnhook
|
||||
|
||||
popnhook is a collection of hook libraries for jubeat providing
|
||||
emulation and various patches to run these games on non BemaniPC hardware and
|
||||
newer Windows versions.
|
||||
|
||||
The hook libraries must be bootstrapped either using [inject](../inject.md) or
|
||||
[launcher](../launcher.md) depending on the version you want to run. Further
|
||||
instructions are given in dedicated readme files for each popnhook version
|
||||
(see below).
|
||||
|
||||
# Versions
|
||||
|
||||
popnhook comes in a few different flavors. The game and its engine changed over
|
||||
the years. Some game versions might require patches/parameters enabled which
|
||||
others don't need or have different AVS versions. Here is the list of supported
|
||||
games:
|
||||
* [popnhook1](popnhook1.md): 15 ADVENTURE, 16 PARTY♪, 17 THE MOVIE, 18 せんごく列伝
|
||||
|
||||
When building bemanitools, independent packages are created for each set of games
|
||||
which are ready to be dropped on top of vanilla AC data dumps. We recommend
|
||||
using pristine dumps to avoid any conflicts with other hardcoded hacks or
|
||||
binary patches.
|
||||
|
||||
# How to run
|
||||
|
||||
To run your game with popnhook, you have to use the inject tool to inject the
|
||||
DLL to the game process. `dist/popn` contains bat scripts with all the
|
||||
important parameters configured. Further parameters can be added but might not
|
||||
be required to run the game with default settings.
|
||||
Further information on how to setup the data for each specific version are
|
||||
elaborated in their dedicated readme files.
|
||||
|
||||
# Eamuse network setup
|
||||
|
||||
Running pop'n music 15 through 18? Modify the appropriate popnhook-15.conf, popnhook-16.conf,
|
||||
popnhook-17.conf, or popnhook-18.conf.
|
||||
|
||||
Running anything newer?
|
||||
* Open the `prop/ea3-config.xml`
|
||||
* Replace the `ea3/network/services` URL with network service URL of your
|
||||
choice (for example http://my.eamuse.com)
|
||||
* Edit the `ea3/id/pcbid`
|
||||
|
||||
# Command line options
|
||||
|
||||
Add the argument *-h* when running inject with popnhook to print help/usage
|
||||
information with a list of parameters you can apply to tweak various things.
|
||||
45
doc/popnhook/popnhook1.md
Normal file
45
doc/popnhook/popnhook1.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Game list
|
||||
|
||||
The following games are compatible with this version of popnhook:
|
||||
* pop'n music 15 ADVENTURE
|
||||
* pop'n music 16 PARTY♪
|
||||
* pop'n music 17 THE MOVIE
|
||||
* pop'n music 18 せんごく列伝
|
||||
|
||||
The games must be bootstrapped using [inject](../inject.md).
|
||||
|
||||
# Data setup and running the game
|
||||
|
||||
Unpack the package containing popnhook1 into the revision folder of your choice.
|
||||
Most likely, you want to target the latest revision you have to run the latest
|
||||
binary of the game with any bugfixes by developers.
|
||||
|
||||
The DLLs in this package should be in the same location as the game DLLs and
|
||||
executable - i.e. all these files should be in the same folder:
|
||||
- `inject.exe`
|
||||
- `popn15.exe` or `popn16.exe` or `popn17.exe` or `popn18.exe`
|
||||
- `popnhook-15.conf` or `popnhook-16.conf` or `popnhook-17.conf` or `popnhook-18.conf`
|
||||
- `eamio.dll`
|
||||
- `popnio.dll`
|
||||
- `libavs-win32.dll`
|
||||
- etc
|
||||
|
||||
Run the `gamestart-15.bat` or `gamestart-16.bat` or `gamestart-17.bat` or `gamestart-18.bat` file as admin.
|
||||
|
||||
# Eamuse network setup
|
||||
|
||||
If you want to run the games online, you have to set a valid PCBID in the
|
||||
configuration file. You also have to set the url of the eamuse server you want
|
||||
to connect to.
|
||||
|
||||
# Eamuse network setup
|
||||
|
||||
If you want to run the games online, you have to set a valid PCBID and EAMID
|
||||
(use the PCBID as the EAMID) in the configuration file or as a command line
|
||||
argument. You also have to set the url of the eamuse server you want to
|
||||
connect to.
|
||||
|
||||
Additional note regarding EAMID: This is provided as the identifier of the
|
||||
"eamuse license" to the server. Depending on the implementation of the server,
|
||||
this can lead to authentication failure resulting in a network error on boot or
|
||||
warning during gameplay.
|
||||
@@ -17,6 +17,7 @@ EXPORTS
|
||||
property_destroy @264 NONAME
|
||||
property_insert_read @23 NONAME
|
||||
property_node_create @316 NONAME
|
||||
property_node_datasize @249 NONAME
|
||||
property_node_refer @268 NONAME
|
||||
property_node_remove @129 NONAME
|
||||
property_psmap_import @102 NONAME
|
||||
|
||||
108
src/main/bemanitools/popnio.h
Normal file
108
src/main/bemanitools/popnio.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef BEMANITOOLS_POPNIO_H
|
||||
#define BEMANITOOLS_POPNIO_H
|
||||
|
||||
/* IO emulation provider for pop'n music. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bemanitools/glue.h"
|
||||
|
||||
/* Bit mapping for the "buttons" word */
|
||||
|
||||
enum popn_io_sys_bit {
|
||||
POPN_IO_SYS_SERVICE = 0x06,
|
||||
POPN_IO_SYS_TEST = 0x07,
|
||||
};
|
||||
|
||||
enum popn_io_button_bit {
|
||||
POPN_IO_BUTTON_1 = 0x08,
|
||||
POPN_IO_BUTTON_2 = 0x09,
|
||||
POPN_IO_BUTTON_3 = 0x0a,
|
||||
POPN_IO_BUTTON_4 = 0x0b,
|
||||
POPN_IO_BUTTON_5 = 0x0c,
|
||||
POPN_IO_BUTTON_6 = 0x0d,
|
||||
POPN_IO_BUTTON_7 = 0x0e,
|
||||
POPN_IO_BUTTON_8 = 0x0f,
|
||||
POPN_IO_BUTTON_9 = 0x10,
|
||||
};
|
||||
|
||||
enum popn_io_light_top_lamp_bit {
|
||||
POPN_LIGHT_HI_LAMP1 = 0x00,
|
||||
POPN_LIGHT_HI_LAMP2 = 0x01,
|
||||
POPN_LIGHT_HI_LAMP3 = 0x02,
|
||||
POPN_LIGHT_HI_LAMP4 = 0x03,
|
||||
POPN_LIGHT_HI_LAMP5 = 0x04,
|
||||
};
|
||||
|
||||
enum popn_io_light_side_lamp_bit {
|
||||
POPN_LIGHT_LEFT_LAMP1 = 0x00,
|
||||
POPN_LIGHT_LEFT_LAMP2 = 0x01,
|
||||
POPN_LIGHT_RIGHT_LAMP1 = 0x02,
|
||||
POPN_LIGHT_RIGHT_LAMP2 = 0x03,
|
||||
};
|
||||
|
||||
enum popn_io_light_switch_lamp_bit {
|
||||
POPN_LIGHT_SW_LAMP1 = 0x00, // Is actually 4 bits wide
|
||||
POPN_LIGHT_SW_LAMP2 = 0x04,
|
||||
POPN_LIGHT_SW_LAMP3 = 0x05,
|
||||
POPN_LIGHT_SW_LAMP4 = 0x06,
|
||||
POPN_LIGHT_SW_LAMP5 = 0x07,
|
||||
POPN_LIGHT_SW_LAMP6 = 0x08,
|
||||
POPN_LIGHT_SW_LAMP7 = 0x09,
|
||||
POPN_LIGHT_SW_LAMP8 = 0x0a,
|
||||
POPN_LIGHT_SW_LAMP9 = 0x0b,
|
||||
};
|
||||
|
||||
/* The first function that will be called on your DLL. You will be supplied
|
||||
with four function pointers that may be used to log messages to the game's
|
||||
log file. See comments in glue.h for further information. */
|
||||
|
||||
void popn_io_set_loggers(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal);
|
||||
|
||||
/* Initialize your pop'n music IO emulation DLL. Thread management functions are
|
||||
provided to you; you must use these functions to create your own threads if
|
||||
you want to make use of the logging functions that are provided to
|
||||
eam_io_set_loggers(). You will also need to pass these thread management
|
||||
functions on to geninput if you intend to make use of that library.
|
||||
|
||||
See glue.h and geninput.h for further details. */
|
||||
|
||||
bool popn_io_init(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy);
|
||||
|
||||
/* Shut down your pop'n music IO emulation DLL */
|
||||
|
||||
void popn_io_fini(void);
|
||||
|
||||
/* Get the state of the buttons. See enums above. */
|
||||
|
||||
uint32_t popn_io_get_buttons(void);
|
||||
|
||||
/* Set the top light state. See enum popn_io_light_top_lamp_bit above. */
|
||||
|
||||
void popn_io_set_top_lights(uint32_t lights);
|
||||
|
||||
/* Set the side light state. See enum popn_io_light_side_lamp_bit above. */
|
||||
|
||||
void popn_io_set_side_lights(uint32_t lights);
|
||||
|
||||
/* Set the button light state. See enum popn_io_light_switch_lamp_bit above. */
|
||||
|
||||
void popn_io_set_button_lights(uint32_t lights);
|
||||
|
||||
/* Set the coin blocker light state. */
|
||||
|
||||
void popn_io_set_coin_blocker_light(bool enabled);
|
||||
|
||||
/* Set the coin counter light state. */
|
||||
|
||||
void popn_io_set_coin_counter_light(bool enabled);
|
||||
|
||||
#endif
|
||||
@@ -54,9 +54,9 @@ uint8_t ezusb_iidx_emu_node_security_mem_v1_process_cmd(
|
||||
uint8_t cmd_id, uint8_t cmd_data, uint8_t cmd_data2)
|
||||
{
|
||||
switch (cmd_id) {
|
||||
case EZUSB_IIDX_SECMEM_CMD_WRITE:
|
||||
log_misc("EZUSB_SECURITY_MEM_V1_CMD_WRITE");
|
||||
return EZUSB_IIDX_SECMEM_CMD_STATUS_V1_WRITE_OK;
|
||||
case EZUSB_IIDX_SECMEM_CMD_INIT:
|
||||
log_misc("EZUSB_SECURITY_MEM_V1_CMD_INIT");
|
||||
return EZUSB_IIDX_SECMEM_CMD_STATUS_V1_INIT_OK;
|
||||
|
||||
default:
|
||||
log_warning(
|
||||
@@ -69,9 +69,9 @@ uint8_t ezusb_iidx_emu_node_security_mem_v2_process_cmd(
|
||||
uint8_t cmd_id, uint8_t cmd_data, uint8_t cmd_data2)
|
||||
{
|
||||
switch (cmd_id) {
|
||||
case EZUSB_IIDX_SECMEM_CMD_WRITE:
|
||||
log_misc("EZUSB_SECURITY_MEM_V2_CMD_WRITE");
|
||||
return EZUSB_IIDX_SECMEM_CMD_STATUS_V2_WRITE_OK;
|
||||
case EZUSB_IIDX_SECMEM_CMD_INIT:
|
||||
log_misc("EZUSB_SECURITY_MEM_V2_CMD_INIT");
|
||||
return EZUSB_IIDX_SECMEM_CMD_STATUS_V2_INIT_OK;
|
||||
|
||||
default:
|
||||
log_warning(
|
||||
|
||||
@@ -174,8 +174,8 @@ uint8_t ezusb_iidx_emu_node_security_plug_process_cmd_v1(
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V1_SECURITY_CONVERSION:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SECURITY_CONVERSION");
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V1_WRITE_DATA:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_WRITE_DATA");
|
||||
/* TODO ? */
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK;
|
||||
|
||||
@@ -201,40 +201,57 @@ uint8_t ezusb_iidx_emu_node_security_plug_process_cmd_v2(
|
||||
uint8_t cmd_id, uint8_t cmd_data, uint8_t cmd_data2)
|
||||
{
|
||||
switch (cmd_id) {
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_INIT:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_INIT");
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SEARCH:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SEARCH");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_mem =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM;
|
||||
ezusb_iidx_emu_node_security_plug_enc_rom_data_seed = cmd_data;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_OK;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SEARCH_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_READ_DATA:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_READ_DATA");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_mem =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_DATA_OK;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_READ_DATA_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_READ_ROM:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_READ_ROM");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_mem =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM;
|
||||
ezusb_iidx_emu_node_security_plug_enc_rom_data_seed = cmd_data;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_ROM_OK;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_READ_ROM_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_WHITE_DONGLE_2:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_WHITE_DONGLE_2");
|
||||
// pop'n music only ever uses slot 2 (white) and slot 4 (black).
|
||||
// If the configuration does not match then it will error out.
|
||||
// IIDX uses slots 2 and 3 and detects what is plugged into each slot so ordering isn't important.
|
||||
// IIDX also reads slot 1's data section but doesn't care what dongle it is?
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_BLACK_DONGLE:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_BLACK_DONGLE");
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_2:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_2");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_3:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_3");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_WHITE_DONGLE:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_WHITE_DONGLE");
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_4:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_4");
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK;
|
||||
|
||||
case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_5:
|
||||
log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_5");
|
||||
// Unknown, not encountered during testing
|
||||
ezusb_iidx_emu_node_security_plug_active_dongle_slot =
|
||||
EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE;
|
||||
return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK;
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
#define EZUSB_IIDX_SECMEM_CMD_H
|
||||
|
||||
enum ezusb_iidx_secmem_command {
|
||||
EZUSB_IIDX_SECMEM_CMD_WRITE = 0x00,
|
||||
EZUSB_IIDX_SECMEM_CMD_INIT = 0x00,
|
||||
};
|
||||
|
||||
enum ezusb_iidx_secmem_command_status_v1 {
|
||||
EZUSB_IIDX_SECMEM_CMD_STATUS_V1_WRITE_OK = 0x60,
|
||||
EZUSB_IIDX_SECMEM_CMD_STATUS_V1_INIT_OK = 0x60,
|
||||
EZUSB_IIDX_SECMEM_CMD_STATUS_V1_FAULT = 0xFE,
|
||||
};
|
||||
|
||||
enum ezusb_iidx_secmem_command_status_v2 {
|
||||
EZUSB_IIDX_SECMEM_CMD_STATUS_V2_WRITE_OK = 0x11,
|
||||
EZUSB_IIDX_SECMEM_CMD_STATUS_V2_INIT_OK = 0x11,
|
||||
EZUSB_IIDX_SECMEM_CMD_STATUS_V2_FAULT = 0xFE,
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ enum ezusb_iidx_secplug_dongle_memory {
|
||||
enum ezusb_iidx_secplug_command_v1 {
|
||||
EZUSB_IIDX_SECPLUG_CMD_V1_READ_ROM = 0x01,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V1_READ_DATA = 0x02,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V1_SECURITY_CONVERSION = 0x03,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V1_WRITE_DATA = 0x03,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_BLACK_DONGLE = 0x04,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_WHITE_DONGLE = 0x05
|
||||
};
|
||||
@@ -25,18 +25,22 @@ enum ezusb_iidx_secplug_command_status_v1 {
|
||||
};
|
||||
|
||||
enum ezusb_iidx_secplug_command_v2 {
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_INIT = 0x01,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SEARCH = 0x01,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_READ_DATA = 0x02,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_WRITE_DATA = 0x03,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_READ_ROM = 0x06,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_WHITE_DONGLE_2 = 0x07,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_BLACK_DONGLE = 0x08,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_WHITE_DONGLE = 0x09
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1 = 0x07,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_2 = 0x08,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_3 = 0x09,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_4 = 0x0a,
|
||||
EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_5 = 0x0b,
|
||||
};
|
||||
|
||||
enum ezusb_iidx_secplug_command_status_v2 {
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_OK = 0x12,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_DATA_OK = 0x13,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_ROM_OK = 0x15,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SEARCH_OK = 0x12,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_READ_DATA_OK = 0x13,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_WRITE_DATA_OK = 0x14,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_READ_ROM_OK = 0x15,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK = 0x16,
|
||||
EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_FAIL = 0xFE
|
||||
};
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#define EZUSB_IIDX_SRAM_CMD_H
|
||||
|
||||
enum ezusb_iidx_sram_command {
|
||||
EZUSB_IIDX_SRAM_CMD_WRITE = 0x03,
|
||||
EZUSB_IIDX_SRAM_CMD_READ = 0x02,
|
||||
EZUSB_IIDX_SRAM_CMD_WRITE = 0x03,
|
||||
EZUSB_IIDX_SRAM_CMD_DONE = 0x04
|
||||
};
|
||||
|
||||
|
||||
10
src/main/ezusb2-popn-emu/Module.mk
Normal file
10
src/main/ezusb2-popn-emu/Module.mk
Normal file
@@ -0,0 +1,10 @@
|
||||
libs += ezusb2-popn-emu
|
||||
|
||||
libs_ezusb2-popn-emu := \
|
||||
ezusb-emu \
|
||||
ezusb-iidx-emu \
|
||||
ezusb-iidx \
|
||||
ezusb2-iidx-emu \
|
||||
|
||||
src_ezusb2-popn-emu := \
|
||||
msg.c \
|
||||
194
src/main/ezusb2-popn-emu/msg.c
Normal file
194
src/main/ezusb2-popn-emu/msg.c
Normal file
@@ -0,0 +1,194 @@
|
||||
#define LOG_MODULE "ezusb2-popn-emu-msg"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bemanitools/popnio.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "ezusb-emu/msg.h"
|
||||
|
||||
#include "ezusb-iidx-emu/msg.h"
|
||||
#include "ezusb-iidx-emu/nodes.h"
|
||||
#include "ezusb-iidx-emu/node-none.h"
|
||||
#include "ezusb-iidx-emu/node-coin.h"
|
||||
#include "ezusb-iidx-emu/node-security-mem.h"
|
||||
#include "ezusb-iidx-emu/node-security-plug.h"
|
||||
|
||||
#include "ezusb2-popn/msg.h"
|
||||
|
||||
#include "util/hex.h"
|
||||
#include "util/log.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static HRESULT ezusb2_popn_emu_msg_interrupt_read(struct iobuf *read);
|
||||
static HRESULT ezusb2_popn_emu_msg_interrupt_write(struct const_iobuf *write);
|
||||
static HRESULT ezusb2_popn_emu_msg_bulk_read(struct iobuf *read);
|
||||
static HRESULT ezusb2_popn_emu_msg_bulk_write(struct const_iobuf *write);
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static struct ezusb_emu_msg_hook ezusb2_popn_emu_msg_hook = {
|
||||
.interrupt_read = ezusb2_popn_emu_msg_interrupt_read,
|
||||
.interrupt_write = ezusb2_popn_emu_msg_interrupt_write,
|
||||
.bulk_read = ezusb2_popn_emu_msg_bulk_read,
|
||||
.bulk_write = ezusb2_popn_emu_msg_bulk_write};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static const struct ezusb_iidx_emu_node *ezusb2_popn_emu_msg_nodes[256] = {
|
||||
[EZUSB_IIDX_MSG_NODE_COIN] = &ezusb_iidx_emu_node_coin,
|
||||
[EZUSB_IIDX_MSG_NODE_NONE] = &ezusb_iidx_emu_node_none,
|
||||
[EZUSB_IIDX_MSG_NODE_EEPROM] = &ezusb_iidx_emu_node_eeprom_v2,
|
||||
[EZUSB_IIDX_MSG_NODE_SECURITY_MEM] = &ezusb_iidx_emu_node_security_mem_v2,
|
||||
[EZUSB_IIDX_MSG_NODE_SECURITY_PLUG] = &ezusb_iidx_emu_node_security_plug_v2,
|
||||
[EZUSB_IIDX_MSG_NODE_SRAM] = &ezusb_iidx_emu_node_sram,
|
||||
[EZUSB_IIDX_MSG_NODE_WDT] = &ezusb_iidx_emu_node_wdt,
|
||||
};
|
||||
|
||||
static uint8_t ezusb2_popn_emu_msg_status = 0;
|
||||
static uint8_t ezusb2_popn_emu_msg_seq_no = 0;
|
||||
static uint8_t ezusb2_popn_emu_msg_read_cur_node = 0;
|
||||
static uint16_t ezusb2_popn_emu_msg_history[10];
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
struct ezusb_emu_msg_hook *ezusb2_popn_emu_msg_init(void)
|
||||
{
|
||||
/* Init all nodes */
|
||||
for (uint32_t i = 0; i < 256; i++) {
|
||||
/* "Constructor" optional */
|
||||
if (ezusb2_popn_emu_msg_nodes[i] &&
|
||||
ezusb2_popn_emu_msg_nodes[i]->init_node) {
|
||||
ezusb2_popn_emu_msg_nodes[i]->init_node();
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ezusb2_popn_emu_msg_history[0], 0xff, sizeof(ezusb2_popn_emu_msg_history));
|
||||
|
||||
return &ezusb2_popn_emu_msg_hook;
|
||||
}
|
||||
|
||||
static HRESULT ezusb2_popn_emu_msg_interrupt_read(struct iobuf *read)
|
||||
{
|
||||
struct ezusb2_popn_msg_interrupt_read_packet *msg_resp =
|
||||
(struct ezusb2_popn_msg_interrupt_read_packet *) read->bytes;
|
||||
|
||||
memset(msg_resp, 0, sizeof(*msg_resp));
|
||||
|
||||
msg_resp->unk0 = 0x03;
|
||||
msg_resp->unk1 = 0x1d;
|
||||
msg_resp->unk2 = 0x85;
|
||||
msg_resp->seq_no = ezusb2_popn_emu_msg_seq_no++;
|
||||
msg_resp->status = ezusb2_popn_emu_msg_status;
|
||||
msg_resp->unk3 = 0x00;
|
||||
msg_resp->coin_count = 0;
|
||||
msg_resp->unk4 = 0xfd;
|
||||
|
||||
msg_resp->io.inverted_pad = ~popn_io_get_buttons();
|
||||
|
||||
msg_resp->unk5 = 0x00;
|
||||
msg_resp->unk6 = 0x7d;
|
||||
msg_resp->unk7 = 0xdf;
|
||||
msg_resp->unk8 = ezusb2_popn_emu_msg_seq_no;
|
||||
|
||||
memcpy(&msg_resp->button_history[0], &ezusb2_popn_emu_msg_history[0], sizeof(uint16_t) * 10);
|
||||
|
||||
read->pos = sizeof(*msg_resp);
|
||||
|
||||
memmove(&ezusb2_popn_emu_msg_history[1], &ezusb2_popn_emu_msg_history[0], sizeof(uint16_t) * 9);
|
||||
ezusb2_popn_emu_msg_history[0] = msg_resp->io.button;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb2_popn_emu_msg_interrupt_write(struct const_iobuf *write)
|
||||
{
|
||||
const struct ezusb2_popn_msg_interrupt_write_packet *msg_req =
|
||||
(const struct ezusb2_popn_msg_interrupt_write_packet *) write->bytes;
|
||||
|
||||
if (write->nbytes < sizeof(*msg_req)) {
|
||||
log_warning("Interrupt write message too small");
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (!ezusb2_popn_emu_msg_nodes[msg_req->node]) {
|
||||
ezusb2_popn_emu_msg_read_cur_node = 0;
|
||||
log_warning(
|
||||
"Unrecognised node in interrupt message: %02x", msg_req->node);
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
popn_io_set_top_lights(msg_req->lamp & 0x1f);
|
||||
popn_io_set_side_lights((msg_req->lamp >> 8) & 0xf);
|
||||
popn_io_set_button_lights((msg_req->lamp >> 20) & 0xfff);
|
||||
popn_io_set_coin_counter_light(((msg_req->lamp >> 12) & 0xf) == 0); // Active low
|
||||
popn_io_set_coin_blocker_light(((msg_req->lamp >> 16) & 0xf) == 0xf);
|
||||
|
||||
/* Remember node for next bulk read */
|
||||
|
||||
ezusb2_popn_emu_msg_read_cur_node = msg_req->node;
|
||||
ezusb2_popn_emu_msg_status =
|
||||
ezusb2_popn_emu_msg_nodes[msg_req->node]->process_cmd(
|
||||
msg_req->cmd, msg_req->cmd_detail[0], msg_req->cmd_detail[1]);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb2_popn_emu_msg_bulk_read(struct iobuf *read)
|
||||
{
|
||||
struct ezusb_iidx_msg_bulk_packet *pkt =
|
||||
(struct ezusb_iidx_msg_bulk_packet *) read->bytes;
|
||||
|
||||
if (read->nbytes < sizeof(*pkt)) {
|
||||
log_warning("Bulk read buffer too small");
|
||||
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
if (!ezusb2_popn_emu_msg_nodes[ezusb2_popn_emu_msg_read_cur_node]) {
|
||||
log_warning(
|
||||
"Bulk read unsupported on cur_node = %d",
|
||||
ezusb2_popn_emu_msg_read_cur_node);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if (!ezusb2_popn_emu_msg_nodes[ezusb2_popn_emu_msg_read_cur_node]
|
||||
->read_packet(pkt)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
read->pos = sizeof(*pkt);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ezusb2_popn_emu_msg_bulk_write(struct const_iobuf *write)
|
||||
{
|
||||
const struct ezusb_iidx_msg_bulk_packet *pkt =
|
||||
(const struct ezusb_iidx_msg_bulk_packet *) write->bytes;
|
||||
|
||||
if (write->nbytes < sizeof(*pkt)) {
|
||||
log_warning("Bulk write packet too small");
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (!ezusb2_popn_emu_msg_nodes[pkt->node]) {
|
||||
log_warning("Bulk write not supported on pkt->node = %02x", pkt->node);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if (!ezusb2_popn_emu_msg_nodes[pkt->node]->write_packet(pkt)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
19
src/main/ezusb2-popn-emu/msg.h
Normal file
19
src/main/ezusb2-popn-emu/msg.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef EZUSB2_POPN_EMU_MSG_H
|
||||
#define EZUSB2_POPN_EMU_MSG_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "ezusb-emu/msg.h"
|
||||
|
||||
/**
|
||||
* Init the fully emulated pop'n msg backend for a EZUSB FX2 (IO2) board
|
||||
*
|
||||
* @return ezusb_emu_msg_hook structure with hook calls for ezusb msg
|
||||
* dispatching
|
||||
*/
|
||||
struct ezusb_emu_msg_hook *ezusb2_popn_emu_msg_init(void);
|
||||
|
||||
#endif
|
||||
14
src/main/ezusb2-popn-shim/Module.mk
Normal file
14
src/main/ezusb2-popn-shim/Module.mk
Normal file
@@ -0,0 +1,14 @@
|
||||
dlls += ezusb2-popn-shim
|
||||
|
||||
ldflags_ezusb2-popn-shim := \
|
||||
-lsetupapi \
|
||||
|
||||
libs_ezusb2-popn-shim := \
|
||||
ezusb2-emu \
|
||||
hook \
|
||||
hooklib \
|
||||
util \
|
||||
|
||||
src_ezusb2-popn-shim := \
|
||||
dllmain.c \
|
||||
proxy.c \
|
||||
40
src/main/ezusb2-popn-shim/dllmain.c
Normal file
40
src/main/ezusb2-popn-shim/dllmain.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <setupapi.h>
|
||||
|
||||
#include "ezusb2-emu/desc.h"
|
||||
#include "ezusb2-emu/device.h"
|
||||
|
||||
#include "hook/pe.h"
|
||||
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
#include "ezusb2-popn-shim/proxy.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define EZUSB_REAL_DLL_FILENAME "ezusb.dll"
|
||||
|
||||
static DWORD(STDCALL *real_entrypoint)(HMODULE self, DWORD reason, void *ctx);
|
||||
|
||||
static HMODULE real_pe = NULL;
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE self, DWORD reason, void *ctx)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH && real_pe == NULL)
|
||||
{
|
||||
pe_hijack_entrypoint(EZUSB_REAL_DLL_FILENAME, &real_entrypoint);
|
||||
|
||||
real_pe = GetModuleHandleA(EZUSB_REAL_DLL_FILENAME);
|
||||
|
||||
ezusb2_proxy_initialize(real_pe);
|
||||
hook_setupapi_init(&ezusb2_emu_desc_device.setupapi);
|
||||
}
|
||||
|
||||
if (real_pe != NULL)
|
||||
return real_entrypoint(real_pe, reason, ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
63
src/main/ezusb2-popn-shim/ezusb2-popn-shim.def
Normal file
63
src/main/ezusb2-popn-shim/ezusb2-popn-shim.def
Normal file
@@ -0,0 +1,63 @@
|
||||
LIBRARY ezusb2-popn-shim
|
||||
|
||||
EXPORTS
|
||||
DllMain@12 @1 NONAME
|
||||
?usbBootSecurity@@YAHPAEHHH@Z=proxy_usb_boot_security
|
||||
?usbBootSecurityAll@@YAHPAEHHH@Z=proxy_usb_boot_security_all
|
||||
?usbBootSecurityAllR@@YAHPAEHHH@Z=proxy_usb_boot_security_all_r
|
||||
?usbCheckAlive@@YAHXZ=proxy_usb_check_alive
|
||||
?usbCheckSecurity@@YAHPAEHHH@Z=proxy_usb_check_security
|
||||
?usbCheckSecurityEep@@YAHH@Z=proxy_usb_check_security_eep
|
||||
?usbCheckSecurityNew@@YAHH@Z=proxy_usb_check_security_new
|
||||
?usbCoinBlocker@@YAHH@Z=proxy_usb_coin_blocker
|
||||
?usbCoinGet2@@YAHPAUCoinParam@@@Z=proxy_usb_coin_get2
|
||||
?usbCoinGet@@YAHH@Z=proxy_usb_coin_get
|
||||
?usbCoinMeterDown@@YAHH@Z=proxy_usb_coin_meter_down
|
||||
?usbCoinMeterUp@@YAHH@Z=proxy_usb_coin_meter_up
|
||||
?usbCoinMode@@YAHH@Z=proxy_usb_coin_mode
|
||||
?usbCoinUp@@YAHH@Z=proxy_usb_coin_up
|
||||
?usbEepRead@@YAHXZ=proxy_usb_eep_read
|
||||
?usbEepReadDone@@YAHPAE@Z=proxy_usb_eep_read_done
|
||||
?usbEepTest@@YAHXZ=proxy_usb_eep_test
|
||||
?usbEepWrite@@YAHPAE@Z=proxy_usb_eep_write
|
||||
?usbEepWriteDone@@YAHXZ=proxy_usb_eep_write_done
|
||||
?usbEnd@@YAHXZ=proxy_usb_end
|
||||
?usbFactoryModeInit@@YAHPAE@Z=proxy_usb_factory_mode_init
|
||||
?usbFirmResult@@YAHXZ=proxy_usb_firm_result
|
||||
?usbGetError@@YAHPAD@Z=proxy_usb_get_error
|
||||
?usbGetKEYID@@YAHPAEH@Z=proxy_usb_get_keyid
|
||||
?usbGetMute@@YAHXZ=proxy_usb_get_mute
|
||||
?usbGetPCBID@@YAHPAE@Z=proxy_usb_get_pcbid
|
||||
?usbGetSecurity@@YAHHPAE@Z=proxy_usb_get_security
|
||||
?usbIsHiSpeed@@YAHXZ=proxy_usb_is_hi_speed
|
||||
?usbLamp@@YAHH@Z=proxy_usb_lamp
|
||||
?usbMute@@YAHH@Z=proxy_usb_mute
|
||||
?usbPadRead@@YAHPAK@Z=proxy_usb_pad_read
|
||||
?usbPadReadLast@@YAHPAE@Z=proxy_usb_pad_read_last
|
||||
?usbReadEepHistory@@YAHPAUEEP_HISTORY@@@Z=proxy_usb_read_eep_history
|
||||
?usbSecurityGetId@@YAHXZ=proxy_usb_security_get_id
|
||||
?usbSecurityGetIdDone@@YAHPAE@Z=proxy_usb_security_get_id_done
|
||||
?usbSecurityInit@@YAHXZ=proxy_usb_security_init
|
||||
?usbSecurityInitDone@@YAHXZ=proxy_usb_security_init_done
|
||||
?usbSecurityRead@@YAHXZ=proxy_usb_security_read
|
||||
?usbSecurityReadDone@@YAHPAE@Z=proxy_usb_security_read_done
|
||||
?usbSecuritySearch@@YAHXZ=proxy_usb_security_search
|
||||
?usbSecuritySearchDone@@YAHXZ=proxy_usb_security_search_done
|
||||
?usbSecuritySelect@@YAHH@Z=proxy_usb_security_select
|
||||
?usbSecuritySelectDone@@YAHXZ=proxy_usb_security_select_done
|
||||
?usbSecurityTest@@YAHH@Z=proxy_usb_security_test
|
||||
?usbSecurityWrite@@YAHPAE@Z=proxy_usb_security_write
|
||||
?usbSecurityWriteDone@@YAHXZ=proxy_usb_security_write_done
|
||||
?usbSetExtIo@@YAHH@Z=proxy_usb_set_ext_io
|
||||
?usbSetupEeprom@@YAHPAEHHH@Z=proxy_usb_setup_eeprom
|
||||
?usbSetupEepromNew@@YAHHPAEHHH@Z=proxy_usb_setup_eeprom_new
|
||||
?usbSetupSecurity@@YAHPAEHHH@Z=proxy_usb_setup_security
|
||||
?usbSetupSecurityComplete@@YAHPAEHHH@Z=proxy_usb_setup_security_complete
|
||||
?usbSetupSecurityCompleteNew@@YAHHPAEHHH@Z=proxy_usb_setup_security_complete_new
|
||||
?usbSetupSecurityNew@@YAHHPAEHHH@Z=proxy_usb_setup_security_new
|
||||
?usbStart@@YAHH@Z=proxy_usb_start
|
||||
?usbStartWithFile@@YAHPAD@Z=proxy_usb_start_with_file
|
||||
?usbWdtReset@@YAHXZ=proxy_usb_wdt_reset
|
||||
?usbWdtStart@@YAHH@Z=proxy_usb_wdt_start
|
||||
?usbWdtStartDone@@YAHXZ=proxy_usb_wdt_start_done
|
||||
?usbWdtStop@@YAHXZ=proxy_usb_wdt_stop
|
||||
612
src/main/ezusb2-popn-shim/proxy.c
Normal file
612
src/main/ezusb2-popn-shim/proxy.c
Normal file
@@ -0,0 +1,612 @@
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
struct CoinParam;
|
||||
struct EEP_HISTORY;
|
||||
|
||||
typedef int32_t (*usb_boot_security_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_boot_security_all_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_boot_security_all_r_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_check_alive_t)();
|
||||
typedef int32_t (*usb_check_security_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_check_security_eep_t)(int32_t param1);
|
||||
typedef int32_t (*usb_check_security_new_t)(int32_t param1);
|
||||
typedef int32_t (*usb_coin_blocker_t)(int32_t param1);
|
||||
typedef int32_t (*usb_coin_get2_t)(struct CoinParam *param1);
|
||||
typedef int32_t (*usb_coin_get_t)(int32_t param1);
|
||||
typedef int32_t (*usb_coin_meter_down_t)(int32_t param1);
|
||||
typedef int32_t (*usb_coin_meter_up_t)(int32_t param1);
|
||||
typedef int32_t (*usb_coin_mode_t)(int32_t param1);
|
||||
typedef int32_t (*usb_coin_up_t)(int32_t param1);
|
||||
typedef int32_t (*usb_eep_read_t)();
|
||||
typedef int32_t (*usb_eep_read_done_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_eep_test_t)();
|
||||
typedef int32_t (*usb_eep_write_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_eep_write_done_t)();
|
||||
typedef int32_t (*usb_end_t)();
|
||||
typedef int32_t (*usb_factory_mode_init_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_firm_result_t)();
|
||||
typedef int32_t (*usb_get_error_t)(char *param1);
|
||||
typedef int32_t (*usb_get_keyid_t)(uint8_t *param1, int32_t param2);
|
||||
typedef int32_t (*usb_get_mute_t)();
|
||||
typedef int32_t (*usb_get_pcbid_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_get_security_t)(int32_t param1, uint8_t *param2);
|
||||
typedef int32_t (*usb_is_hi_speed_t)();
|
||||
typedef int32_t (*usb_lamp_t)(int32_t param1);
|
||||
typedef int32_t (*usb_mute_t)(int32_t param1);
|
||||
typedef int32_t (*usb_pad_read_t)(uint32_t *param1);
|
||||
typedef int32_t (*usb_pad_read_last_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_read_eep_history_t)(struct EEP_HISTORY *param1);
|
||||
typedef int32_t (*usb_security_get_id_t)();
|
||||
typedef int32_t (*usb_security_get_id_done_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_security_init_t)();
|
||||
typedef int32_t (*usb_security_init_done_t)();
|
||||
typedef int32_t (*usb_security_read_t)();
|
||||
typedef int32_t (*usb_security_read_done_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_security_search_t)();
|
||||
typedef int32_t (*usb_security_search_done_t)();
|
||||
typedef int32_t (*usb_security_select_t)(int32_t param1);
|
||||
typedef int32_t (*usb_security_select_done_t)();
|
||||
typedef int32_t (*usb_security_test_t)(int32_t param1);
|
||||
typedef int32_t (*usb_security_write_t)(uint8_t *param1);
|
||||
typedef int32_t (*usb_security_write_done_t)();
|
||||
typedef int32_t (*usb_set_ext_io_t)(int32_t param1);
|
||||
typedef int32_t (*usb_setup_eeprom_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_setup_eeprom_new_t)(int32_t param1, uint8_t *param2, int32_t param3, int32_t param4, int32_t param5);
|
||||
typedef int32_t (*usb_setup_security_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_setup_security_complete_t)(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4);
|
||||
typedef int32_t (*usb_setup_security_complete_new_t)(int32_t param1, uint8_t *param2, int32_t param3, int32_t param4, int32_t param5);
|
||||
typedef int32_t (*usb_setup_security_new_t)(int32_t param1, uint8_t *param2, int32_t param3, int32_t param4, int32_t param5);
|
||||
typedef int32_t (*usb_start_t)(int32_t param1);
|
||||
typedef int32_t (*usb_start_with_file_t)(char *param1);
|
||||
typedef int32_t (*usb_wdt_reset_t)();
|
||||
typedef int32_t (*usb_wdt_start_t)(int32_t param1);
|
||||
typedef int32_t (*usb_wdt_start_done_t)();
|
||||
typedef int32_t (*usb_wdt_stop_t)();
|
||||
|
||||
static usb_boot_security_t real_usb_boot_security;
|
||||
static usb_boot_security_all_t real_usb_boot_security_all;
|
||||
static usb_boot_security_all_r_t real_usb_boot_security_all_r;
|
||||
static usb_check_alive_t real_usb_check_alive;
|
||||
static usb_check_security_t real_usb_check_security;
|
||||
static usb_check_security_eep_t real_usb_check_security_eep;
|
||||
static usb_check_security_new_t real_usb_check_security_new;
|
||||
static usb_coin_blocker_t real_usb_coin_blocker;
|
||||
static usb_coin_get2_t real_usb_coin_get2;
|
||||
static usb_coin_get_t real_usb_coin_get;
|
||||
static usb_coin_meter_down_t real_usb_coin_meter_down;
|
||||
static usb_coin_meter_up_t real_usb_coin_meter_up;
|
||||
static usb_coin_mode_t real_usb_coin_mode;
|
||||
static usb_coin_up_t real_usb_coin_up;
|
||||
static usb_eep_read_t real_usb_eep_read;
|
||||
static usb_eep_read_done_t real_usb_eep_read_done;
|
||||
static usb_eep_test_t real_usb_eep_test;
|
||||
static usb_eep_write_t real_usb_eep_write;
|
||||
static usb_eep_write_done_t real_usb_eep_write_done;
|
||||
static usb_end_t real_usb_end;
|
||||
static usb_factory_mode_init_t real_usb_factory_mode_init;
|
||||
static usb_firm_result_t real_usb_firm_result;
|
||||
static usb_get_error_t real_usb_get_error;
|
||||
static usb_get_keyid_t real_usb_get_keyid;
|
||||
static usb_get_mute_t real_usb_get_mute;
|
||||
static usb_get_pcbid_t real_usb_get_pcbid;
|
||||
static usb_get_security_t real_usb_get_security;
|
||||
static usb_is_hi_speed_t real_usb_is_hi_speed;
|
||||
static usb_lamp_t real_usb_lamp;
|
||||
static usb_mute_t real_usb_mute;
|
||||
static usb_pad_read_t real_usb_pad_read;
|
||||
static usb_pad_read_last_t real_usb_pad_read_last;
|
||||
static usb_read_eep_history_t real_usb_read_eep_history;
|
||||
static usb_security_get_id_t real_usb_security_get_id;
|
||||
static usb_security_get_id_done_t real_usb_security_get_id_done;
|
||||
static usb_security_init_t real_usb_security_init;
|
||||
static usb_security_init_done_t real_usb_security_init_done;
|
||||
static usb_security_read_t real_usb_security_read;
|
||||
static usb_security_read_done_t real_usb_security_read_done;
|
||||
static usb_security_search_t real_usb_security_search;
|
||||
static usb_security_search_done_t real_usb_security_search_done;
|
||||
static usb_security_select_t real_usb_security_select;
|
||||
static usb_security_select_done_t real_usb_security_select_done;
|
||||
static usb_security_test_t real_usb_security_test;
|
||||
static usb_security_write_t real_usb_security_write;
|
||||
static usb_security_write_done_t real_usb_security_write_done;
|
||||
static usb_set_ext_io_t real_usb_set_ext_io;
|
||||
static usb_setup_eeprom_t real_usb_setup_eeprom;
|
||||
static usb_setup_eeprom_new_t real_usb_setup_eeprom_new;
|
||||
static usb_setup_security_t real_usb_setup_security;
|
||||
static usb_setup_security_complete_t real_usb_setup_security_complete;
|
||||
static usb_setup_security_complete_new_t real_usb_setup_security_complete_new;
|
||||
static usb_setup_security_new_t real_usb_setup_security_new;
|
||||
static usb_start_t real_usb_start;
|
||||
static usb_start_with_file_t real_usb_start_with_file;
|
||||
static usb_wdt_reset_t real_usb_wdt_reset;
|
||||
static usb_wdt_start_t real_usb_wdt_start;
|
||||
static usb_wdt_start_done_t real_usb_wdt_start_done;
|
||||
static usb_wdt_stop_t real_usb_wdt_stop;
|
||||
|
||||
static bool proxy_is_initialized = false;
|
||||
|
||||
void ezusb2_proxy_initialize(HMODULE pe)
|
||||
{
|
||||
if (proxy_is_initialized)
|
||||
return;
|
||||
|
||||
log_assert(pe != NULL);
|
||||
|
||||
proxy_is_initialized = true;
|
||||
|
||||
real_usb_boot_security = (usb_boot_security_t)GetProcAddress(pe, "?usbBootSecurity@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_boot_security);
|
||||
|
||||
real_usb_boot_security_all = (usb_boot_security_all_t)GetProcAddress(pe, "?usbBootSecurityAll@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_boot_security_all);
|
||||
|
||||
real_usb_boot_security_all_r = (usb_boot_security_all_r_t)GetProcAddress(pe, "?usbBootSecurityAllR@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_boot_security_all_r);
|
||||
|
||||
real_usb_check_alive = (usb_check_alive_t)GetProcAddress(pe, "?usbCheckAlive@@YAHXZ");
|
||||
log_assert(real_usb_check_alive);
|
||||
|
||||
real_usb_check_security = (usb_check_security_t)GetProcAddress(pe, "?usbCheckSecurity@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_check_security);
|
||||
|
||||
real_usb_check_security_eep = (usb_check_security_eep_t)GetProcAddress(pe, "?usbCheckSecurityEep@@YAHH@Z");
|
||||
log_assert(real_usb_check_security_eep);
|
||||
|
||||
real_usb_check_security_new = (usb_check_security_new_t)GetProcAddress(pe, "?usbCheckSecurityNew@@YAHH@Z");
|
||||
log_assert(real_usb_check_security_new);
|
||||
|
||||
real_usb_coin_blocker = (usb_coin_blocker_t)GetProcAddress(pe, "?usbCoinBlocker@@YAHH@Z");
|
||||
log_assert(real_usb_coin_blocker);
|
||||
|
||||
real_usb_coin_get2 = (usb_coin_get2_t)GetProcAddress(pe, "?usbCoinGet2@@YAHPAUCoinParam@@@Z");
|
||||
log_assert(real_usb_coin_get2);
|
||||
|
||||
real_usb_coin_get = (usb_coin_get_t)GetProcAddress(pe, "?usbCoinGet@@YAHH@Z");
|
||||
log_assert(real_usb_coin_get);
|
||||
|
||||
real_usb_coin_meter_down = (usb_coin_meter_down_t)GetProcAddress(pe, "?usbCoinMeterDown@@YAHH@Z");
|
||||
log_assert(real_usb_coin_meter_down);
|
||||
|
||||
real_usb_coin_meter_up = (usb_coin_meter_up_t)GetProcAddress(pe, "?usbCoinMeterUp@@YAHH@Z");
|
||||
log_assert(real_usb_coin_meter_up);
|
||||
|
||||
real_usb_coin_mode = (usb_coin_mode_t)GetProcAddress(pe, "?usbCoinMode@@YAHH@Z");
|
||||
log_assert(real_usb_coin_mode);
|
||||
|
||||
real_usb_coin_up = (usb_coin_up_t)GetProcAddress(pe, "?usbCoinUp@@YAHH@Z");
|
||||
log_assert(real_usb_coin_up);
|
||||
|
||||
real_usb_eep_read = (usb_eep_read_t)GetProcAddress(pe, "?usbEepRead@@YAHXZ");
|
||||
log_assert(real_usb_eep_read);
|
||||
|
||||
real_usb_eep_read_done = (usb_eep_read_done_t)GetProcAddress(pe, "?usbEepReadDone@@YAHPAE@Z");
|
||||
log_assert(real_usb_eep_read_done);
|
||||
|
||||
real_usb_eep_test = (usb_eep_test_t)GetProcAddress(pe, "?usbEepTest@@YAHXZ");
|
||||
log_assert(real_usb_eep_test);
|
||||
|
||||
real_usb_eep_write = (usb_eep_write_t)GetProcAddress(pe, "?usbEepWrite@@YAHPAE@Z");
|
||||
log_assert(real_usb_eep_write);
|
||||
|
||||
real_usb_eep_write_done = (usb_eep_write_done_t)GetProcAddress(pe, "?usbEepWriteDone@@YAHXZ");
|
||||
log_assert(real_usb_eep_write_done);
|
||||
|
||||
real_usb_end = (usb_end_t)GetProcAddress(pe, "?usbEnd@@YAHXZ");
|
||||
log_assert(real_usb_end);
|
||||
|
||||
real_usb_factory_mode_init = (usb_factory_mode_init_t)GetProcAddress(pe, "?usbFactoryModeInit@@YAHPAE@Z");
|
||||
log_assert(real_usb_factory_mode_init);
|
||||
|
||||
real_usb_firm_result = (usb_firm_result_t)GetProcAddress(pe, "?usbFirmResult@@YAHXZ");
|
||||
log_assert(real_usb_firm_result);
|
||||
|
||||
real_usb_get_error = (usb_get_error_t)GetProcAddress(pe, "?usbGetError@@YAHPAD@Z");
|
||||
log_assert(real_usb_get_error);
|
||||
|
||||
real_usb_get_keyid = (usb_get_keyid_t)GetProcAddress(pe, "?usbGetKEYID@@YAHPAEH@Z");
|
||||
log_assert(real_usb_get_keyid);
|
||||
|
||||
real_usb_get_mute = (usb_get_mute_t)GetProcAddress(pe, "?usbGetMute@@YAHXZ");
|
||||
log_assert(real_usb_get_mute);
|
||||
|
||||
real_usb_get_pcbid = (usb_get_pcbid_t)GetProcAddress(pe, "?usbGetPCBID@@YAHPAE@Z");
|
||||
log_assert(real_usb_get_pcbid);
|
||||
|
||||
real_usb_get_security = (usb_get_security_t)GetProcAddress(pe, "?usbGetSecurity@@YAHHPAE@Z");
|
||||
log_assert(real_usb_get_security);
|
||||
|
||||
real_usb_is_hi_speed = (usb_is_hi_speed_t)GetProcAddress(pe, "?usbIsHiSpeed@@YAHXZ");
|
||||
log_assert(real_usb_is_hi_speed);
|
||||
|
||||
real_usb_lamp = (usb_lamp_t)GetProcAddress(pe, "?usbLamp@@YAHH@Z");
|
||||
log_assert(real_usb_lamp);
|
||||
|
||||
real_usb_mute = (usb_mute_t)GetProcAddress(pe, "?usbMute@@YAHH@Z");
|
||||
log_assert(real_usb_mute);
|
||||
|
||||
real_usb_pad_read = (usb_pad_read_t)GetProcAddress(pe, "?usbPadRead@@YAHPAK@Z");
|
||||
log_assert(real_usb_pad_read);
|
||||
|
||||
real_usb_pad_read_last = (usb_pad_read_last_t)GetProcAddress(pe, "?usbPadReadLast@@YAHPAE@Z");
|
||||
log_assert(real_usb_pad_read_last);
|
||||
|
||||
real_usb_read_eep_history = (usb_read_eep_history_t)GetProcAddress(pe, "?usbReadEepHistory@@YAHPAUEEP_HISTORY@@@Z");
|
||||
log_assert(real_usb_read_eep_history);
|
||||
|
||||
real_usb_security_get_id = (usb_security_get_id_t)GetProcAddress(pe, "?usbSecurityGetId@@YAHXZ");
|
||||
log_assert(real_usb_security_get_id);
|
||||
|
||||
real_usb_security_get_id_done = (usb_security_get_id_done_t)GetProcAddress(pe, "?usbSecurityGetIdDone@@YAHPAE@Z");
|
||||
log_assert(real_usb_security_get_id_done);
|
||||
|
||||
real_usb_security_init = (usb_security_init_t)GetProcAddress(pe, "?usbSecurityInit@@YAHXZ");
|
||||
log_assert(real_usb_security_init);
|
||||
|
||||
real_usb_security_init_done = (usb_security_init_done_t)GetProcAddress(pe, "?usbSecurityInitDone@@YAHXZ");
|
||||
log_assert(real_usb_security_init_done);
|
||||
|
||||
real_usb_security_read = (usb_security_read_t)GetProcAddress(pe, "?usbSecurityRead@@YAHXZ");
|
||||
log_assert(real_usb_security_read);
|
||||
|
||||
real_usb_security_read_done = (usb_security_read_done_t)GetProcAddress(pe, "?usbSecurityReadDone@@YAHPAE@Z");
|
||||
log_assert(real_usb_security_read_done);
|
||||
|
||||
real_usb_security_search = (usb_security_search_t)GetProcAddress(pe, "?usbSecuritySearch@@YAHXZ");
|
||||
log_assert(real_usb_security_search);
|
||||
|
||||
real_usb_security_search_done = (usb_security_search_done_t)GetProcAddress(pe, "?usbSecuritySearchDone@@YAHXZ");
|
||||
log_assert(real_usb_security_search_done);
|
||||
|
||||
real_usb_security_select = (usb_security_select_t)GetProcAddress(pe, "?usbSecuritySelect@@YAHH@Z");
|
||||
log_assert(real_usb_security_select);
|
||||
|
||||
real_usb_security_select_done = (usb_security_select_done_t)GetProcAddress(pe, "?usbSecuritySelectDone@@YAHXZ");
|
||||
log_assert(real_usb_security_select_done);
|
||||
|
||||
real_usb_security_test = (usb_security_test_t)GetProcAddress(pe, "?usbSecurityTest@@YAHH@Z");
|
||||
log_assert(real_usb_security_test);
|
||||
|
||||
real_usb_security_write = (usb_security_write_t)GetProcAddress(pe, "?usbSecurityWrite@@YAHPAE@Z");
|
||||
log_assert(real_usb_security_write);
|
||||
|
||||
real_usb_security_write_done = (usb_security_write_done_t)GetProcAddress(pe, "?usbSecurityWriteDone@@YAHXZ");
|
||||
log_assert(real_usb_security_write_done);
|
||||
|
||||
real_usb_set_ext_io = (usb_set_ext_io_t)GetProcAddress(pe, "?usbSetExtIo@@YAHH@Z");
|
||||
log_assert(real_usb_set_ext_io);
|
||||
|
||||
real_usb_setup_eeprom = (usb_setup_eeprom_t)GetProcAddress(pe, "?usbSetupEeprom@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_setup_eeprom);
|
||||
|
||||
real_usb_setup_eeprom_new = (usb_setup_eeprom_new_t)GetProcAddress(pe, "?usbSetupEepromNew@@YAHHPAEHHH@Z");
|
||||
log_assert(real_usb_setup_eeprom_new);
|
||||
|
||||
real_usb_setup_security = (usb_setup_security_t)GetProcAddress(pe, "?usbSetupSecurity@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_setup_security);
|
||||
|
||||
real_usb_setup_security_complete = (usb_setup_security_complete_t)GetProcAddress(pe, "?usbSetupSecurityComplete@@YAHPAEHHH@Z");
|
||||
log_assert(real_usb_setup_security_complete);
|
||||
|
||||
real_usb_setup_security_complete_new = (usb_setup_security_complete_new_t)GetProcAddress(pe, "?usbSetupSecurityCompleteNew@@YAHHPAEHHH@Z");
|
||||
log_assert(real_usb_setup_security_complete_new);
|
||||
|
||||
real_usb_setup_security_new = (usb_setup_security_new_t)GetProcAddress(pe, "?usbSetupSecurityNew@@YAHHPAEHHH@Z");
|
||||
log_assert(real_usb_setup_security_new);
|
||||
|
||||
real_usb_start = (usb_start_t)GetProcAddress(pe, "?usbStart@@YAHH@Z");
|
||||
log_assert(real_usb_start);
|
||||
|
||||
real_usb_start_with_file = (usb_start_with_file_t)GetProcAddress(pe, "?usbStartWithFile@@YAHPAD@Z");
|
||||
log_assert(real_usb_start_with_file);
|
||||
|
||||
real_usb_wdt_reset = (usb_wdt_reset_t)GetProcAddress(pe, "?usbWdtReset@@YAHXZ");
|
||||
log_assert(real_usb_wdt_reset);
|
||||
|
||||
real_usb_wdt_start = (usb_wdt_start_t)GetProcAddress(pe, "?usbWdtStart@@YAHH@Z");
|
||||
log_assert(real_usb_wdt_start);
|
||||
|
||||
real_usb_wdt_start_done = (usb_wdt_start_done_t)GetProcAddress(pe, "?usbWdtStartDone@@YAHXZ");
|
||||
log_assert(real_usb_wdt_start_done);
|
||||
|
||||
real_usb_wdt_stop = (usb_wdt_stop_t)GetProcAddress(pe, "?usbWdtStop@@YAHXZ");
|
||||
log_assert(real_usb_wdt_stop);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_boot_security(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_boot_security(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_boot_security_all(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_boot_security_all(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_boot_security_all_r(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_boot_security_all_r(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_check_alive()
|
||||
{
|
||||
return real_usb_check_alive();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_check_security(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_check_security(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_check_security_eep(int32_t param1)
|
||||
{
|
||||
return real_usb_check_security_eep(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_check_security_new(int32_t param1)
|
||||
{
|
||||
return real_usb_check_security_new(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_blocker(int32_t param1)
|
||||
{
|
||||
return real_usb_coin_blocker(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_get2(struct CoinParam *param1)
|
||||
{
|
||||
return real_usb_coin_get2(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_get(int32_t param1)
|
||||
{
|
||||
return real_usb_coin_get(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_meter_down(int32_t param1)
|
||||
{
|
||||
return real_usb_coin_meter_down(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_meter_up(int32_t param1)
|
||||
{
|
||||
return real_usb_coin_meter_up(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_mode(int32_t param1)
|
||||
{
|
||||
return real_usb_coin_mode(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_coin_up(int32_t param1)
|
||||
{
|
||||
return real_usb_coin_up(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_eep_read()
|
||||
{
|
||||
return real_usb_eep_read();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_eep_read_done(uint8_t *param1)
|
||||
{
|
||||
return real_usb_eep_read_done(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_eep_test()
|
||||
{
|
||||
return real_usb_eep_test();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_eep_write(uint8_t *param1)
|
||||
{
|
||||
return real_usb_eep_write(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_eep_write_done()
|
||||
{
|
||||
return real_usb_eep_write_done();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_end()
|
||||
{
|
||||
return real_usb_end();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_factory_mode_init(uint8_t *param1)
|
||||
{
|
||||
return real_usb_factory_mode_init(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_firm_result()
|
||||
{
|
||||
return real_usb_firm_result();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_get_error(char *param1)
|
||||
{
|
||||
return real_usb_get_error(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_get_keyid(uint8_t *param1, int32_t param2)
|
||||
{
|
||||
return real_usb_get_keyid(param1, param2);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_get_mute()
|
||||
{
|
||||
return real_usb_get_mute();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_get_pcbid(uint8_t *param1)
|
||||
{
|
||||
return real_usb_get_pcbid(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_get_security(int32_t param1, uint8_t *param2)
|
||||
{
|
||||
return real_usb_get_security(param1, param2);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_is_hi_speed()
|
||||
{
|
||||
return real_usb_is_hi_speed();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_lamp(int32_t param1)
|
||||
{
|
||||
return real_usb_lamp(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_mute(int32_t param1)
|
||||
{
|
||||
return real_usb_mute(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_pad_read(uint32_t *param1)
|
||||
{
|
||||
return real_usb_pad_read(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_pad_read_last(uint8_t *param1)
|
||||
{
|
||||
return real_usb_pad_read_last(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_read_eep_history(struct EEP_HISTORY *param1)
|
||||
{
|
||||
return real_usb_read_eep_history(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_get_id()
|
||||
{
|
||||
return real_usb_security_get_id();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_get_id_done(uint8_t *param1)
|
||||
{
|
||||
return real_usb_security_get_id_done(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_init()
|
||||
{
|
||||
return real_usb_security_init();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_init_done()
|
||||
{
|
||||
return real_usb_security_init_done();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_read()
|
||||
{
|
||||
return real_usb_security_read();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_read_done(uint8_t *param1)
|
||||
{
|
||||
return real_usb_security_read_done(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_search()
|
||||
{
|
||||
return real_usb_security_search();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_search_done()
|
||||
{
|
||||
return real_usb_security_search_done();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_select(int32_t param1)
|
||||
{
|
||||
return real_usb_security_select(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_select_done()
|
||||
{
|
||||
return real_usb_security_select_done();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_test(int32_t param1)
|
||||
{
|
||||
return real_usb_security_test(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_write(uint8_t *param1)
|
||||
{
|
||||
return real_usb_security_write(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_security_write_done()
|
||||
{
|
||||
return real_usb_security_write_done();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_set_ext_io(int32_t param1)
|
||||
{
|
||||
return real_usb_set_ext_io(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_setup_eeprom(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_setup_eeprom(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_setup_eeprom_new(int32_t param1, uint8_t *param2, int32_t param3, int32_t param4, int32_t param5)
|
||||
{
|
||||
return real_usb_setup_eeprom_new(param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_setup_security(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_setup_security(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_setup_security_complete(uint8_t *param1, int32_t param2, int32_t param3, int32_t param4)
|
||||
{
|
||||
return real_usb_setup_security_complete(param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_setup_security_complete_new(int32_t param1, uint8_t *param2, int32_t param3, int32_t param4, int32_t param5)
|
||||
{
|
||||
return real_usb_setup_security_complete_new(param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_setup_security_new(int32_t param1, uint8_t *param2, int32_t param3, int32_t param4, int32_t param5)
|
||||
{
|
||||
return real_usb_setup_security_new(param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_start(int32_t param1)
|
||||
{
|
||||
return real_usb_start(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_start_with_file(char *param1)
|
||||
{
|
||||
return real_usb_start_with_file(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_wdt_reset()
|
||||
{
|
||||
return real_usb_wdt_reset();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_wdt_start(int32_t param1)
|
||||
{
|
||||
return real_usb_wdt_start(param1);
|
||||
}
|
||||
|
||||
int32_t proxy_usb_wdt_start_done()
|
||||
{
|
||||
return real_usb_wdt_start_done();
|
||||
}
|
||||
|
||||
int32_t proxy_usb_wdt_stop()
|
||||
{
|
||||
return real_usb_wdt_stop();
|
||||
}
|
||||
6
src/main/ezusb2-popn-shim/proxy.h
Normal file
6
src/main/ezusb2-popn-shim/proxy.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef EZUSB2_POPN_SHIM_PROXY_H
|
||||
#define EZUSB2_POPN_SHIM_PROXY_H
|
||||
|
||||
void ezusb2_proxy_initialize(HMODULE pe);
|
||||
|
||||
#endif
|
||||
87
src/main/ezusb2-popn/msg.h
Normal file
87
src/main/ezusb2-popn/msg.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef EZUSB2_POPN_MSG_H
|
||||
#define EZUSB2_POPN_MSG_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ezusb2_popn_msg_interrupt_write_packet {
|
||||
uint8_t unk0;
|
||||
uint8_t unk1;
|
||||
uint8_t node;
|
||||
uint8_t cmd;
|
||||
uint8_t cmd_detail[2];
|
||||
uint8_t unknown[2];
|
||||
uint32_t lamp;
|
||||
/* Pad to 64 byte total size because the endpoint expects this buffer size.
|
||||
Requests are hanging on ioctl calls otherwise. */
|
||||
uint8_t unknown2[52];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ezusb2_popn_msg_interrupt_read_packet {
|
||||
/*
|
||||
Pad mappings:
|
||||
0: unknown/not used
|
||||
1: unknown/not used
|
||||
2: unknown/not used
|
||||
3: unknown/not used
|
||||
4: unknown/not used
|
||||
5: unknown/not used
|
||||
6: service
|
||||
7: test
|
||||
|
||||
8: button 1
|
||||
9: button 2
|
||||
10: button 3
|
||||
11: button 4
|
||||
12: button 5
|
||||
13: button 6
|
||||
14: button 7
|
||||
15: button 8
|
||||
|
||||
16: button 9
|
||||
17: unknown/not used
|
||||
18: unknown/not used
|
||||
19: unknown/not used
|
||||
20: unknown/not used
|
||||
21: unknown/not used
|
||||
22: coin
|
||||
23: unknown/not used
|
||||
|
||||
24: dipsw 1
|
||||
25: dipsw 2
|
||||
26: dipsw 3
|
||||
27: dipsw 4
|
||||
28: unknown/not used
|
||||
29: unknown/not used
|
||||
30: unknown/not used
|
||||
31: unknown/not used
|
||||
*/
|
||||
uint8_t unk0; /* 0x03 */
|
||||
uint8_t unk1; /* 0x1d */
|
||||
uint8_t unk2; /* 0x85 */
|
||||
uint8_t seq_no;
|
||||
uint8_t status;
|
||||
uint8_t unk3; /* 0x00 */
|
||||
uint8_t coin_count;
|
||||
uint8_t unk4; /* 0xfd */
|
||||
union {
|
||||
uint32_t inverted_pad;
|
||||
struct {
|
||||
uint8_t sys; /* test/service bitfield */
|
||||
uint16_t button; /* button bitfield */
|
||||
uint8_t dipsw; /* dip switches */
|
||||
};
|
||||
} io;
|
||||
uint8_t unk5; /* 0x00 */
|
||||
uint8_t unk6; /* 0x7d */
|
||||
uint8_t unk7; /* 0xdf */
|
||||
uint8_t unk8; /* seq no 2? */
|
||||
uint16_t button_history[10];
|
||||
uint8_t padding[28];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
@@ -220,3 +220,96 @@ HRESULT pe_patch(void *dest, const void *src, size_t nbytes)
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const pe_thunk_t *pe_thunk_get_first(HMODULE pe, const pe_iid_t *iid)
|
||||
{
|
||||
pe_thunk_t *thunk;
|
||||
|
||||
assert(pe != NULL);
|
||||
assert(iid != NULL);
|
||||
|
||||
thunk = pe_offset(pe, iid->FirstThunk);
|
||||
|
||||
if (thunk == NULL || thunk->u1.AddressOfData == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return thunk;
|
||||
}
|
||||
|
||||
const pe_thunk_t *pe_thunk_get_next(const pe_thunk_t *thunk)
|
||||
{
|
||||
const IMAGE_THUNK_DATA *thunk_next;
|
||||
|
||||
assert(thunk != NULL);
|
||||
|
||||
thunk_next = thunk + 1;
|
||||
|
||||
if (thunk_next == NULL || thunk_next->u1.AddressOfData == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return thunk_next;
|
||||
}
|
||||
|
||||
void *pe_thunk_get_resolved_function(HMODULE target_pe, HMODULE import_pe, const pe_thunk_t *thunk)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
assert(target_pe != NULL);
|
||||
assert(import_pe != NULL);
|
||||
assert(thunk != NULL);
|
||||
|
||||
if (thunk->u1.AddressOfData != 0) {
|
||||
if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
|
||||
LPCSTR functionOrdinal = (LPCSTR)IMAGE_ORDINAL(thunk->u1.Ordinal);
|
||||
addr = (void *)GetProcAddress(import_pe, functionOrdinal);
|
||||
} else {
|
||||
PIMAGE_IMPORT_BY_NAME functionName = pe_offset(target_pe, thunk->u1.AddressOfData);
|
||||
addr = (void *)GetProcAddress(import_pe, functionName->Name);
|
||||
}
|
||||
} else {
|
||||
addr = NULL;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void pe_resolve_imports(HMODULE target_pe)
|
||||
{
|
||||
for (const pe_iid_t *iid = pe_iid_get_first(target_pe); iid != NULL; iid = pe_iid_get_next(target_pe, iid)) {
|
||||
const char *iid_name;
|
||||
HMODULE imported_pe;
|
||||
|
||||
iid_name = pe_iid_get_name(target_pe, iid);
|
||||
imported_pe = LoadLibraryA(iid_name);
|
||||
assert(imported_pe != NULL);
|
||||
|
||||
for (const pe_thunk_t *thunk = pe_thunk_get_first(target_pe, iid); thunk != NULL; thunk = pe_thunk_get_next(thunk)) {
|
||||
void *addr;
|
||||
|
||||
addr = pe_thunk_get_resolved_function(target_pe, imported_pe, thunk);
|
||||
|
||||
if (addr != NULL) {
|
||||
pe_patch((void*)&thunk->u1.Function, &addr, sizeof(PDWORD));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT pe_hijack_entrypoint(const char *filename, dll_entry_t *orig_entry)
|
||||
{
|
||||
HMODULE pe;
|
||||
|
||||
pe = LoadLibraryExA(filename, NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||
|
||||
if (!pe) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
pe_resolve_imports(pe);
|
||||
|
||||
*orig_entry = pe_get_entry_point(pe);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <stdint.h>
|
||||
|
||||
typedef IMAGE_IMPORT_DESCRIPTOR pe_iid_t;
|
||||
typedef IMAGE_THUNK_DATA pe_thunk_t;
|
||||
|
||||
typedef DWORD (CALLBACK *dll_entry_t)(HMODULE self, DWORD reason, void *ctx);
|
||||
|
||||
struct pe_iat_entry {
|
||||
const char *name;
|
||||
@@ -25,3 +28,6 @@ HRESULT pe_iid_get_iat_entry(
|
||||
void *pe_get_export(HMODULE pe, const char *name, uint16_t ord);
|
||||
void *pe_get_entry_point(HMODULE pe);
|
||||
HRESULT pe_patch(void *dest, const void *src, size_t nbytes);
|
||||
|
||||
HRESULT pe_hijack_entrypoint(const char *filename, dll_entry_t *orig_entry);
|
||||
void pe_resolve_imports(HMODULE target_pe);
|
||||
28
src/main/iidxhook5-cn/Module.mk
Normal file
28
src/main/iidxhook5-cn/Module.mk
Normal file
@@ -0,0 +1,28 @@
|
||||
avsdlls += iidxhook5-cn
|
||||
|
||||
ldflags_iidxhook5-cn := \
|
||||
-liphlpapi \
|
||||
|
||||
deplibs_iidxhook5-cn := \
|
||||
avs \
|
||||
|
||||
libs_iidxhook5-cn := \
|
||||
iidxhook-util \
|
||||
ezusb-emu \
|
||||
ezusb2-emu \
|
||||
ezusb2-iidx-emu \
|
||||
ezusb-iidx-emu \
|
||||
security \
|
||||
eamio \
|
||||
acioemu \
|
||||
hook \
|
||||
hooklib \
|
||||
iidxio \
|
||||
cconfig \
|
||||
util \
|
||||
ezusb \
|
||||
|
||||
src_iidxhook5-cn := \
|
||||
avs-boot.c \
|
||||
path.c \
|
||||
dllmain.c \
|
||||
103
src/main/iidxhook5-cn/avs-boot.c
Normal file
103
src/main/iidxhook5-cn/avs-boot.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#define LOG_MODULE "avs-boot"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "iidxhook5-cn/avs-boot.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static void (*real_avs_boot)(
|
||||
struct property_node *config,
|
||||
void *std_heap,
|
||||
size_t sz_std_heap,
|
||||
void *avs_heap,
|
||||
size_t sz_avs_heap,
|
||||
avs_log_writer_t log_writer,
|
||||
void *log_context);
|
||||
|
||||
static void my_avs_boot(
|
||||
struct property_node *config,
|
||||
void *std_heap,
|
||||
size_t sz_std_heap,
|
||||
void *avs_heap,
|
||||
size_t sz_avs_heap,
|
||||
avs_log_writer_t log_writer,
|
||||
void *log_context);
|
||||
|
||||
static const struct hook_symbol iidxhook5_cn_log_hook_syms[] = {
|
||||
{.name = "XC058ba50000f4",
|
||||
.patch = my_avs_boot,
|
||||
.link = (void **) &real_avs_boot},
|
||||
};
|
||||
|
||||
static void avs_boot_replace_property_uint32(
|
||||
struct property_node *node, const char *name, uint32_t val)
|
||||
{
|
||||
struct property_node *tmp;
|
||||
|
||||
tmp = property_search(NULL, node, name);
|
||||
|
||||
if (tmp) {
|
||||
property_node_remove(tmp);
|
||||
}
|
||||
|
||||
property_node_create(NULL, node, PSMAP_TYPE_U32, name, val);
|
||||
}
|
||||
|
||||
static void avs_boot_replace_property_str(
|
||||
struct property_node *node, const char *name, const char *val)
|
||||
{
|
||||
struct property_node *tmp;
|
||||
|
||||
tmp = property_search(NULL, node, name);
|
||||
|
||||
if (tmp) {
|
||||
property_node_remove(tmp);
|
||||
}
|
||||
|
||||
tmp = property_node_create(NULL, node, PROPERTY_TYPE_STR, name, val);
|
||||
|
||||
if (tmp) {
|
||||
property_node_datasize(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void my_avs_boot(
|
||||
struct property_node *config,
|
||||
void *std_heap,
|
||||
size_t sz_std_heap,
|
||||
void *avs_heap,
|
||||
size_t sz_avs_heap,
|
||||
avs_log_writer_t log_writer,
|
||||
void *log_context)
|
||||
{
|
||||
log_info("Called my_avs_boot");
|
||||
|
||||
avs_boot_replace_property_uint32(config, "log/level", 4);
|
||||
avs_boot_replace_property_str(config, "fs/root/device", ".");
|
||||
|
||||
real_avs_boot(
|
||||
config,
|
||||
std_heap,
|
||||
sz_std_heap,
|
||||
avs_heap,
|
||||
sz_avs_heap,
|
||||
log_writer_debug,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void iidxhook5_cn_avs_boot_init()
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"libavs-win32.dll",
|
||||
iidxhook5_cn_log_hook_syms,
|
||||
lengthof(iidxhook5_cn_log_hook_syms));
|
||||
|
||||
log_info("Inserted avs log hooks");
|
||||
}
|
||||
10
src/main/iidxhook5-cn/avs-boot.h
Normal file
10
src/main/iidxhook5-cn/avs-boot.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef IIDXHOOK5_CN_AVS_BOOT_H
|
||||
#define IIDXHOOK5_CN_AVS_BOOT_H
|
||||
|
||||
/**
|
||||
* Initialize hooking of avs_boot. This re-enables avs logging
|
||||
* and injects a few important settings.
|
||||
*/
|
||||
void iidxhook5_cn_avs_boot_init();
|
||||
|
||||
#endif
|
||||
222
src/main/iidxhook5-cn/dllmain.c
Normal file
222
src/main/iidxhook5-cn/dllmain.c
Normal file
@@ -0,0 +1,222 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
#include "bemanitools/iidxio.h"
|
||||
|
||||
#include "cconfig/cconfig-hook.h"
|
||||
|
||||
#include "ezusb-iidx-emu/node-security-plug.h"
|
||||
|
||||
#include "ezusb2-emu/desc.h"
|
||||
#include "ezusb2-emu/device.h"
|
||||
|
||||
#include "ezusb2-iidx-emu/msg.h"
|
||||
|
||||
#include "hook/d3d9.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/acp.h"
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
#include "iidxhook5-cn/avs-boot.h"
|
||||
#include "iidxhook5-cn/path.h"
|
||||
|
||||
#include "iidxhook-util/acio.h"
|
||||
#include "iidxhook-util/config-eamuse.h"
|
||||
#include "iidxhook-util/config-gfx.h"
|
||||
#include "iidxhook-util/config-io.h"
|
||||
#include "iidxhook-util/config-sec.h"
|
||||
#include "iidxhook-util/d3d9.h"
|
||||
#include "iidxhook-util/settings.h"
|
||||
|
||||
#include "security/rp-sign-key.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define IIDXHOOK5_CN_INFO_HEADER \
|
||||
"iidxhook for tricoro CN" \
|
||||
", build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV)
|
||||
#define IIDXHOOK5_CN_CMD_USAGE \
|
||||
"Usage: inject.exe iidxhook5-cn.dll <bm2dx.exe> [options...]"
|
||||
|
||||
static ATOM WINAPI my_RegisterClassA(const WNDCLASSA *lpWndClass);
|
||||
static ATOM(WINAPI *real_RegisterClassA)(const WNDCLASSA *lpWndClass);
|
||||
static bool iidxhook_init_check;
|
||||
|
||||
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
|
||||
iidxhook_util_d3d9_irp_handler,
|
||||
};
|
||||
|
||||
static const struct hook_symbol init_hook_user32_syms[] = {
|
||||
{.name = "RegisterClassA",
|
||||
.patch = my_RegisterClassA,
|
||||
.link = (void **) &real_RegisterClassA},
|
||||
};
|
||||
|
||||
static struct iidxhook_config_io config_io;
|
||||
|
||||
static void
|
||||
iidxhook5_cn_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx)
|
||||
{
|
||||
struct iidxhook_util_d3d9_config d3d9_config;
|
||||
|
||||
iidxhook_util_d3d9_init_config(&d3d9_config);
|
||||
|
||||
d3d9_config.windowed = config_gfx->windowed;
|
||||
d3d9_config.framed = config_gfx->framed;
|
||||
d3d9_config.override_window_width = config_gfx->window_width;
|
||||
d3d9_config.override_window_height = config_gfx->window_height;
|
||||
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
|
||||
d3d9_config.pci_vid = config_gfx->pci_id_vid;
|
||||
d3d9_config.pci_pid = config_gfx->pci_id_pid;
|
||||
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
|
||||
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
|
||||
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
|
||||
d3d9_config.forced_refresh_rate = config_gfx->forced_refresh_rate;
|
||||
d3d9_config.device_adapter = config_gfx->device_adapter;
|
||||
|
||||
iidxhook_util_d3d9_configure(&d3d9_config);
|
||||
|
||||
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenProcess is basically used for hooks in exe games,
|
||||
* but since it does not exist in this game, RegisterClassA is used instead.
|
||||
*/
|
||||
static ATOM WINAPI my_RegisterClassA(const WNDCLASSA *lpWndClass)
|
||||
{
|
||||
struct cconfig *config;
|
||||
|
||||
struct iidxhook_util_config_eamuse config_eamuse;
|
||||
struct iidxhook_config_gfx config_gfx;
|
||||
struct iidxhook_config_sec config_sec;
|
||||
|
||||
if (iidxhook_init_check) {
|
||||
return real_RegisterClassA(lpWndClass);
|
||||
}
|
||||
|
||||
iidxhook_init_check = true;
|
||||
|
||||
log_info("-------------------------------------------------------------");
|
||||
log_info("--------------- Begin iidxhook RegisterClassA ---------------");
|
||||
log_info("-------------------------------------------------------------");
|
||||
|
||||
config = cconfig_init();
|
||||
|
||||
iidxhook_util_config_eamuse_init(config);
|
||||
iidxhook_config_gfx_init(config);
|
||||
iidxhook_config_io_init(config);
|
||||
iidxhook_config_sec_init(config);
|
||||
|
||||
if (!cconfig_hook_config_init(
|
||||
config,
|
||||
IIDXHOOK5_CN_INFO_HEADER "\n" IIDXHOOK5_CN_CMD_USAGE,
|
||||
CCONFIG_CMD_USAGE_OUT_DBG)) {
|
||||
cconfig_finit(config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
iidxhook_util_config_eamuse_get(&config_eamuse, config);
|
||||
iidxhook_config_gfx_get(&config_gfx, config);
|
||||
iidxhook_config_io_get(&config_io, config);
|
||||
iidxhook_config_sec_get(&config_sec, config);
|
||||
|
||||
cconfig_finit(config);
|
||||
|
||||
log_info(IIDXHOOK5_CN_INFO_HEADER);
|
||||
log_info("Initializing iidxhook...");
|
||||
|
||||
/**
|
||||
* This game is using a black round plug for game license management instead of a black usb dongle.
|
||||
* No white dongle hooks applies since the game does not have network functionality.
|
||||
* Also, card readers are not used/checked; no card reader hooks required.
|
||||
*/
|
||||
ezusb_iidx_emu_node_security_plug_set_boot_version(
|
||||
&config_sec.boot_version);
|
||||
ezusb_iidx_emu_node_security_plug_set_boot_seeds(config_sec.boot_seeds);
|
||||
ezusb_iidx_emu_node_security_plug_set_plug_black_sign_key(
|
||||
&security_rp_sign_key_black_iidx);
|
||||
ezusb_iidx_emu_node_security_plug_set_plug_black_mcode(
|
||||
&config_sec.black_plug_mcode);
|
||||
ezusb_iidx_emu_node_security_plug_set_pcbid(&config_eamuse.pcbid);
|
||||
|
||||
iidxhook5_cn_setup_d3d9_hooks(&config_gfx);
|
||||
|
||||
if (!config_io.disable_io_emu) {
|
||||
log_info("Starting IIDX IO backend");
|
||||
|
||||
iidx_io_set_loggers(
|
||||
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
|
||||
|
||||
if (!iidx_io_init(
|
||||
avs_thread_create, avs_thread_join, avs_thread_destroy)) {
|
||||
log_fatal("Initializing IIDX IO backend failed");
|
||||
}
|
||||
} else {
|
||||
log_info("IIDX IO emulation backend disabled");
|
||||
}
|
||||
|
||||
if (!config_io.disable_card_reader_emu) {
|
||||
log_misc("Initializing card reader backend");
|
||||
|
||||
eam_io_set_loggers(
|
||||
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
|
||||
|
||||
if (!eam_io_init(
|
||||
avs_thread_create, avs_thread_join, avs_thread_destroy)) {
|
||||
log_fatal("Initializing card reader backend failed");
|
||||
}
|
||||
} else {
|
||||
log_info("Card reader emulation backend disabled");
|
||||
}
|
||||
|
||||
/* Set up IO emulation hooks _after_ IO API setup to allow
|
||||
API implementations with real IO devices */
|
||||
iohook_push_handler(ezusb2_emu_device_dispatch_irp);
|
||||
iohook_push_handler(iidxhook_util_acio_dispatch_irp);
|
||||
iohook_push_handler(settings_hook_dispatch_irp);
|
||||
|
||||
if (!config_io.disable_io_emu) {
|
||||
hook_setupapi_init(&ezusb2_emu_desc_device.setupapi);
|
||||
ezusb2_emu_device_hook_init(ezusb2_iidx_emu_msg_init());
|
||||
}
|
||||
|
||||
log_info("-------------------------------------------------------------");
|
||||
log_info("---------------- End iidxhook RegisterClassA ----------------");
|
||||
log_info("-------------------------------------------------------------");
|
||||
|
||||
return real_RegisterClassA(lpWndClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook library for tricoro CN
|
||||
*/
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
|
||||
{
|
||||
if (reason != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
log_to_writer(log_writer_debug, NULL);
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"user32.dll",
|
||||
init_hook_user32_syms,
|
||||
lengthof(init_hook_user32_syms));
|
||||
|
||||
iidxhook5_cn_path_init();
|
||||
iidxhook5_cn_avs_boot_init();
|
||||
acp_hook_init();
|
||||
settings_hook_init();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
4
src/main/iidxhook5-cn/iidxhook5-cn.def
Normal file
4
src/main/iidxhook5-cn/iidxhook5-cn.def
Normal file
@@ -0,0 +1,4 @@
|
||||
LIBRARY iidxhook5-cn
|
||||
|
||||
EXPORTS
|
||||
DllMain@12 @1 NONAME
|
||||
104
src/main/iidxhook5-cn/path.c
Normal file
104
src/main/iidxhook5-cn/path.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#define LOG_MODULE "path"
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "iidxhook5-cn/path.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
#define PATH_A "D:/JDZ-001/contents/"
|
||||
#define PATH_W L"D:/JDZ-001/contents/"
|
||||
|
||||
static HANDLE WINAPI my_CreateFileW(
|
||||
LPCWSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
static HANDLE(WINAPI *real_CreateFileW)(
|
||||
LPCWSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
|
||||
static HANDLE WINAPI my_FindFirstFileA(
|
||||
LPCSTR lpFileName,
|
||||
LPWIN32_FIND_DATAA lpFindFileData);
|
||||
static HANDLE(WINAPI *real_FindFirstFileA)(
|
||||
LPCSTR lpFileName,
|
||||
LPWIN32_FIND_DATAA lpFindFileData);
|
||||
|
||||
static const struct hook_symbol iidxhook5_cn_path_hook_syms[] = {
|
||||
{.name = "CreateFileW",
|
||||
.patch = my_CreateFileW,
|
||||
.link = (void **) &real_CreateFileW},
|
||||
{.name = "FindFirstFileA",
|
||||
.patch = my_FindFirstFileA,
|
||||
.link = (void **) &real_FindFirstFileA},
|
||||
};
|
||||
|
||||
static HANDLE WINAPI my_CreateFileW(
|
||||
LPCWSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile)
|
||||
{
|
||||
if (lpFileName != NULL && wcsstr(lpFileName, PATH_W) == lpFileName) {
|
||||
wchar_t relative[MAX_PATH] = L".";
|
||||
wstr_cat(relative, MAX_PATH, lpFileName + wcslen(PATH_W) - 1);
|
||||
return real_CreateFileW(
|
||||
relative,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
lpSecurityAttributes,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
hTemplateFile);
|
||||
}
|
||||
|
||||
return real_CreateFileW(
|
||||
lpFileName,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
lpSecurityAttributes,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
hTemplateFile);
|
||||
}
|
||||
|
||||
static HANDLE WINAPI my_FindFirstFileA(
|
||||
LPCSTR lpFileName,
|
||||
LPWIN32_FIND_DATAA lpFindFileData)
|
||||
{
|
||||
if (lpFileName != NULL && strstr(lpFileName, PATH_A) == lpFileName) {
|
||||
char relative[MAX_PATH] = ".";
|
||||
str_cat(relative, MAX_PATH, lpFileName + strlen(PATH_A) - 1);
|
||||
return real_FindFirstFileA(relative, lpFindFileData);
|
||||
}
|
||||
|
||||
return real_FindFirstFileA(lpFileName, lpFindFileData);
|
||||
}
|
||||
|
||||
void iidxhook5_cn_path_init()
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
iidxhook5_cn_path_hook_syms,
|
||||
lengthof(iidxhook5_cn_path_hook_syms));
|
||||
|
||||
log_info("Inserted path hooks");
|
||||
}
|
||||
6
src/main/iidxhook5-cn/path.h
Normal file
6
src/main/iidxhook5-cn/path.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef IIDXHOOK5_CN_PATH_H
|
||||
#define IIDXHOOK5_CN_PATH_H
|
||||
|
||||
void iidxhook5_cn_path_init();
|
||||
|
||||
#endif
|
||||
@@ -8,8 +8,8 @@ libs_inject := \
|
||||
util \
|
||||
|
||||
src_inject := \
|
||||
main.c \
|
||||
debugger.c \
|
||||
logger.c \
|
||||
main.c \
|
||||
options.c \
|
||||
version.c \
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "util/signal.h"
|
||||
#include "util/str.h"
|
||||
|
||||
#define MM_ALLOCATION_GRANULARITY 0x10000
|
||||
|
||||
struct debugger_thread_params {
|
||||
const char *app_name;
|
||||
char *cmd_line;
|
||||
@@ -27,6 +29,14 @@ static HANDLE debugger_ready_event;
|
||||
|
||||
static PROCESS_INFORMATION pi;
|
||||
|
||||
static PVOID load_nt_header_from_process(HANDLE hProcess,
|
||||
HMODULE hModule,
|
||||
PIMAGE_NT_HEADERS32 pNtHeader);
|
||||
|
||||
static HMODULE enumerate_modules_in_process(HANDLE hProcess,
|
||||
HMODULE hModuleLast,
|
||||
PIMAGE_NT_HEADERS32 pNtHeader);
|
||||
|
||||
// Source:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/memory/obtaining-a-file-name-from-a-file-handle
|
||||
static bool
|
||||
@@ -548,6 +558,156 @@ alloc_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT debugger_pe_patch_remote(HANDLE hProcess, void *dest, const void *src, size_t nbytes)
|
||||
{
|
||||
DWORD old_protect;
|
||||
BOOL ok;
|
||||
|
||||
log_assert(dest != NULL);
|
||||
log_assert(src != NULL);
|
||||
|
||||
ok = VirtualProtectEx(
|
||||
hProcess,
|
||||
dest,
|
||||
nbytes,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
&old_protect);
|
||||
|
||||
if (!ok) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
ok = WriteProcessMemory(
|
||||
hProcess, dest, src, nbytes, NULL);
|
||||
|
||||
if (!ok) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
ok = VirtualProtectEx(
|
||||
hProcess,
|
||||
dest,
|
||||
nbytes,
|
||||
old_protect,
|
||||
&old_protect);
|
||||
|
||||
if (!ok) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool debugger_replace_dll_iat(const char *expected_dll, const char *replacement_path_dll)
|
||||
{
|
||||
log_assert(expected_dll);
|
||||
log_assert(replacement_path_dll);
|
||||
|
||||
HMODULE hModule = NULL;
|
||||
HMODULE hLast = NULL;
|
||||
void *remote_addr;
|
||||
|
||||
// Find EXE base in process memory
|
||||
IMAGE_NT_HEADERS inh;
|
||||
for (;;) {
|
||||
memset(&inh, 0, sizeof(IMAGE_NT_HEADERS));
|
||||
|
||||
if ((hLast = enumerate_modules_in_process(pi.hProcess, hLast, &inh)) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
|
||||
hModule = hLast;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hModule == NULL) {
|
||||
log_warning("Couldn't find target EXE for hooking");
|
||||
goto inject_fail;
|
||||
}
|
||||
|
||||
// Search through import table if it exists and replace the target DLL with our DLL filename
|
||||
PBYTE pbModule = (PBYTE)hModule;
|
||||
PIMAGE_SECTION_HEADER pRemoteSectionHeaders
|
||||
= (PIMAGE_SECTION_HEADER)((PBYTE)pbModule
|
||||
+ sizeof(inh.Signature)
|
||||
+ sizeof(inh.FileHeader)
|
||||
+ inh.FileHeader.SizeOfOptionalHeader);
|
||||
size_t total_size = inh.OptionalHeader.SizeOfHeaders;
|
||||
|
||||
IMAGE_SECTION_HEADER header;
|
||||
for (DWORD n = 0; n < inh.FileHeader.NumberOfSections; ++n) {
|
||||
if (!ReadProcessMemory(pi.hProcess, pRemoteSectionHeaders + n, &header, sizeof(header), NULL)) {
|
||||
log_warning("Couldn't read section header: %lu", GetLastError());
|
||||
goto inject_fail;
|
||||
}
|
||||
|
||||
size_t new_total_size = header.VirtualAddress + header.Misc.VirtualSize;
|
||||
if (new_total_size > total_size)
|
||||
total_size = new_total_size;
|
||||
}
|
||||
|
||||
remote_addr = VirtualAllocEx(
|
||||
pi.hProcess,
|
||||
pbModule + total_size + MM_ALLOCATION_GRANULARITY,
|
||||
strlen(replacement_path_dll) + 1,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
|
||||
log_assert(remote_addr != NULL);
|
||||
|
||||
debugger_pe_patch_remote(
|
||||
pi.hProcess, remote_addr, replacement_path_dll, strlen(replacement_path_dll));
|
||||
|
||||
if (inh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0) {
|
||||
PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule
|
||||
+ inh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
DWORD size = 0;
|
||||
while (inh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0
|
||||
|| size < inh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) {
|
||||
IMAGE_IMPORT_DESCRIPTOR ImageImport;
|
||||
if (!ReadProcessMemory(pi.hProcess, pImageImport, &ImageImport, sizeof(ImageImport), NULL)) {
|
||||
log_warning("Couldn't read import: %lu", GetLastError());
|
||||
goto inject_fail;
|
||||
}
|
||||
|
||||
if (ImageImport.Name == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char name[MAX_PATH] = {0};
|
||||
if (ReadProcessMemory(pi.hProcess, pbModule + ImageImport.Name, name, sizeof(name), NULL)) {
|
||||
// log_misc("\tImport DLL: %ld %s", ImageImport.Name, name);
|
||||
|
||||
if (strcmp(name, expected_dll) == 0) {
|
||||
//log_misc("Replacing %s with %s", name, replacement_path_dll, (void*)pImageImport);
|
||||
|
||||
ImageImport.Name = (DWORD)((PBYTE)remote_addr - pbModule);
|
||||
|
||||
debugger_pe_patch_remote(
|
||||
pi.hProcess,
|
||||
pImageImport,
|
||||
&ImageImport,
|
||||
sizeof(ImageImport));
|
||||
}
|
||||
}
|
||||
|
||||
pImageImport++;
|
||||
size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
}
|
||||
} else {
|
||||
log_warning("Couldn't find import table, can't hook DLL\n");
|
||||
goto inject_fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
inject_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool debugger_resume_process()
|
||||
{
|
||||
log_info("Resuming remote process...");
|
||||
@@ -593,3 +753,90 @@ void debugger_finit(bool failure)
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
|
||||
// Helper functions based on Microsoft Detours
|
||||
static PVOID load_nt_header_from_process(HANDLE hProcess,
|
||||
HMODULE hModule,
|
||||
PIMAGE_NT_HEADERS32 pNtHeader)
|
||||
{
|
||||
PBYTE pbModule = (PBYTE)hModule;
|
||||
|
||||
memset(pNtHeader, 0, sizeof(*pNtHeader));
|
||||
|
||||
if (pbModule == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
memset(&mbi, 0, sizeof(mbi));
|
||||
|
||||
if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMAGE_DOS_HEADER idh;
|
||||
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
|
||||
log_warning("Could not read DOS header: %lu", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (idh.e_magic != IMAGE_DOS_SIGNATURE ||
|
||||
(DWORD)idh.e_lfanew > mbi.RegionSize ||
|
||||
(DWORD)idh.e_lfanew < sizeof(idh)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew,
|
||||
pNtHeader, sizeof(*pNtHeader), NULL)) {
|
||||
log_warning("Could not read NT header: %lu", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pbModule + idh.e_lfanew;
|
||||
}
|
||||
|
||||
static HMODULE enumerate_modules_in_process(HANDLE hProcess,
|
||||
HMODULE hModuleLast,
|
||||
PIMAGE_NT_HEADERS32 pNtHeader)
|
||||
{
|
||||
PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
|
||||
|
||||
memset(pNtHeader, 0, sizeof(*pNtHeader));
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
memset(&mbi, 0, sizeof(mbi));
|
||||
|
||||
// Find the next memory region that contains a mapped PE image.
|
||||
for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
|
||||
if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Usermode address space has such an unaligned region size always at the
|
||||
// end and only at the end.
|
||||
if ((mbi.RegionSize & 0xfff) == 0xfff) {
|
||||
break;
|
||||
}
|
||||
if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip uncommitted regions and guard pages.
|
||||
if ((mbi.State != MEM_COMMIT) ||
|
||||
((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
|
||||
(mbi.Protect & PAGE_GUARD)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (load_nt_header_from_process(hProcess, (HMODULE)pbLast, pNtHeader)) {
|
||||
return (HMODULE)pbLast;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
/**
|
||||
* Initialize inject's logger backend.
|
||||
*
|
||||
*
|
||||
* This takes care of hooking and merging the different log
|
||||
* streams, e.g. inject's local logging and inject's debugger
|
||||
* receiving remote logging events.
|
||||
*
|
||||
*
|
||||
* @param log_file_path Path to the file to log to or NULL to
|
||||
* disable.
|
||||
*/
|
||||
@@ -17,21 +17,21 @@
|
||||
|
||||
/**
|
||||
* Initialize the debugger.
|
||||
*
|
||||
*
|
||||
* This creates the remote process of the provided application.
|
||||
*
|
||||
*
|
||||
* The remote process is created suspended. This allows you to
|
||||
* to some more process setup tasks like injecting hook DLLs
|
||||
* before you call debugger_resume_process to actually start
|
||||
* execution of it.
|
||||
*
|
||||
*
|
||||
* The actual debugging runs in a dedicated thread which spawns
|
||||
* the process, waits for and dispatches debug events.
|
||||
*
|
||||
*
|
||||
* However, if you want to attach a remote debugger, you have to
|
||||
* set the parameter local_debugger to false. Then, the debugger
|
||||
* will only create the remote process and monitor it.
|
||||
*
|
||||
*
|
||||
* @param local_debugger True to attach inject's local debugger,
|
||||
* false to allow attaching a remote
|
||||
* debugger with enhanced features.
|
||||
@@ -44,18 +44,28 @@ bool debugger_init(bool local_debugger, const char *app_name, char *cmd_line);
|
||||
|
||||
/**
|
||||
* Inject a DLL into the remote process.
|
||||
*
|
||||
*
|
||||
* @param path_dll Path to the dll to inject.
|
||||
* @return true if sucessful, false on error.
|
||||
*/
|
||||
bool debugger_inject_dll(const char *path_dll);
|
||||
|
||||
/**
|
||||
* Inject a DLL into the remote process by replacing its reference in
|
||||
* the import table.
|
||||
*
|
||||
* @param expected_dll Name of dll to override.
|
||||
* @param replacement_path_dll Name of dll to inject.
|
||||
* @return true if sucessful, false on error.
|
||||
*/
|
||||
bool debugger_replace_dll_iat(const char *expected_dll, const char *replacement_path_dll);
|
||||
|
||||
/**
|
||||
* Wait/block for a remote debugger to attach to the remote process.
|
||||
*
|
||||
*
|
||||
* You only need to call this if you specified local_debugger = false
|
||||
* on debugger_init.
|
||||
*
|
||||
*
|
||||
* @return True if successfull and a remote debugger attached, false
|
||||
* on error.
|
||||
*/
|
||||
@@ -63,21 +73,21 @@ bool debugger_wait_for_remote_debugger();
|
||||
|
||||
/**
|
||||
* Resume the remote process.
|
||||
*
|
||||
*
|
||||
* Make sure to call this once you are done with setting it up.
|
||||
*
|
||||
*
|
||||
* @return true on success, false on error.
|
||||
*/
|
||||
bool debugger_resume_process();
|
||||
|
||||
/**
|
||||
* Wait for the remote process to exit.
|
||||
*/
|
||||
*/
|
||||
void debugger_wait_process_exit();
|
||||
|
||||
/**
|
||||
* Cleanup the debugger.
|
||||
*
|
||||
*
|
||||
* @param failure Set this to true if you have to cleanup due to
|
||||
* a failure of another debugger function call.
|
||||
* Otherwise, set this to false.
|
||||
|
||||
@@ -80,8 +80,15 @@ verify_hook_dlls_exist(int argc, char **argv, uint32_t hook_dll_count)
|
||||
DWORD dll_path_length;
|
||||
|
||||
for (uint32_t i = 0; i < hook_dll_count; i++) {
|
||||
dll_path_length =
|
||||
SearchPath(NULL, argv[i + 1], NULL, MAX_PATH, dll_path, NULL);
|
||||
char *iat_hook = strstr(argv[i + 1], "=");
|
||||
|
||||
if (iat_hook) {
|
||||
dll_path_length =
|
||||
SearchPath(NULL, iat_hook + 1, NULL, MAX_PATH, dll_path, NULL);
|
||||
} else {
|
||||
dll_path_length =
|
||||
SearchPath(NULL, argv[i + 1], NULL, MAX_PATH, dll_path, NULL);
|
||||
}
|
||||
|
||||
if (dll_path_length == 0) {
|
||||
log_warning(
|
||||
@@ -94,6 +101,26 @@ verify_hook_dlls_exist(int argc, char **argv, uint32_t hook_dll_count)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool inject_iat_hook_dlls(uint32_t hooks, char **argv)
|
||||
{
|
||||
log_assert(argv);
|
||||
|
||||
log_info("Injecting IAT hook DLLs...");
|
||||
|
||||
for (int i = 0; i < hooks; i++) {
|
||||
char *iat_hook = strstr(argv[i + 1], "=");
|
||||
|
||||
if (!iat_hook)
|
||||
continue;
|
||||
|
||||
*iat_hook = '\0';
|
||||
debugger_replace_dll_iat(argv[i + 1], iat_hook+1);
|
||||
*iat_hook = '=';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool inject_hook_dlls(uint32_t hooks, char **argv)
|
||||
{
|
||||
log_assert(argv);
|
||||
@@ -101,6 +128,11 @@ static bool inject_hook_dlls(uint32_t hooks, char **argv)
|
||||
log_info("Injecting hook DLLs...");
|
||||
|
||||
for (int i = 0; i < hooks; i++) {
|
||||
char *iat_hook = strstr(argv[i + 1], "=");
|
||||
|
||||
if (iat_hook)
|
||||
continue;
|
||||
|
||||
if (!debugger_inject_dll(argv[i + 1])) {
|
||||
return false;
|
||||
}
|
||||
@@ -155,6 +187,10 @@ int main(int argc, char **argv)
|
||||
goto debugger_init_fail;
|
||||
}
|
||||
|
||||
if (!inject_iat_hook_dlls(hooks, argv)) {
|
||||
goto inject_hook_dlls_fail;
|
||||
}
|
||||
|
||||
if (!inject_hook_dlls(hooks, argv)) {
|
||||
goto inject_hook_dlls_fail;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ void options_print_usage(void)
|
||||
"You can specify one or multiple hook.dll files, e.g. inject.exe "
|
||||
"hook1.dll hook2.dll app.exe"
|
||||
"\n"
|
||||
"An IAT replacement early injection can be specified using the syntax orig.dll=hook.dll"
|
||||
"\n"
|
||||
" The following options can be specified after the exe path:\n"
|
||||
"\n"
|
||||
" -D Enable debugging output\n"
|
||||
|
||||
@@ -214,7 +214,11 @@ int main(int argc, const char **argv)
|
||||
|
||||
/* Load game DLL */
|
||||
|
||||
module_context_init(&module, options.module);
|
||||
if (options.iat_hook_dlls.nitems > 0) {
|
||||
module_context_init_with_iat_hooks(&module, options.module, &options.iat_hook_dlls);
|
||||
} else {
|
||||
module_context_init(&module, options.module);
|
||||
}
|
||||
|
||||
/* Load hook DLLs */
|
||||
|
||||
|
||||
@@ -1,94 +1,247 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "imports/avs.h"
|
||||
#include "imports/eapki.h"
|
||||
|
||||
#include "launcher/module.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
void module_context_init(struct module_context *module, const char *path)
|
||||
{
|
||||
log_assert(module != NULL);
|
||||
log_assert(path != NULL);
|
||||
|
||||
module->dll = LoadLibrary(path);
|
||||
|
||||
if (module->dll == NULL) {
|
||||
LPSTR buffer;
|
||||
DWORD err = GetLastError();
|
||||
|
||||
FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &buffer,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (err == ERROR_MOD_NOT_FOUND) {
|
||||
log_warning("%s is likely missing dependencies", path);
|
||||
log_warning("Do you have vcredist/directx runtimes installed?");
|
||||
}
|
||||
|
||||
log_fatal("%s: Failed to load game DLL: %s", path, buffer);
|
||||
|
||||
LocalFree(buffer);
|
||||
}
|
||||
|
||||
module->path = str_dup(path);
|
||||
}
|
||||
|
||||
bool module_context_invoke_init(
|
||||
const struct module_context *module,
|
||||
char *sidcode,
|
||||
struct property_node *app_config)
|
||||
{
|
||||
dll_entry_init_t init;
|
||||
|
||||
log_assert(module != NULL);
|
||||
log_assert(sidcode != NULL);
|
||||
log_assert(app_config != NULL);
|
||||
|
||||
init = (void *) GetProcAddress(module->dll, "dll_entry_init");
|
||||
|
||||
if (init == NULL) {
|
||||
log_fatal(
|
||||
"%s: dll_entry_init not found. Is this a game DLL?", module->path);
|
||||
}
|
||||
|
||||
return init(sidcode, app_config);
|
||||
}
|
||||
|
||||
bool module_context_invoke_main(const struct module_context *module)
|
||||
{
|
||||
/* GCC warns if you call a variable "main" */
|
||||
dll_entry_main_t main_;
|
||||
|
||||
log_assert(module != NULL);
|
||||
|
||||
main_ = (void *) GetProcAddress(module->dll, "dll_entry_main");
|
||||
|
||||
if (main_ == NULL) {
|
||||
log_fatal(
|
||||
"%s: dll_entry_main not found. Is this a game DLL?", module->path);
|
||||
}
|
||||
|
||||
return main_();
|
||||
}
|
||||
|
||||
void module_context_fini(struct module_context *module)
|
||||
{
|
||||
if (module == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(module->path);
|
||||
|
||||
if (module->dll != NULL) {
|
||||
FreeLibrary(module->dll);
|
||||
}
|
||||
}
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/pe.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
#include "imports/eapki.h"
|
||||
|
||||
#include "launcher/module.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
#define MM_ALLOCATION_GRANULARITY 0x10000
|
||||
|
||||
|
||||
static bool module_replace_dll_iat(HMODULE hModule, struct array *iat_hook_dlls)
|
||||
{
|
||||
log_assert(hModule);
|
||||
log_assert(iat_hook_dlls);
|
||||
|
||||
if (iat_hook_dlls->nitems == 0)
|
||||
return true;
|
||||
|
||||
PBYTE pbModule = (PBYTE)hModule;
|
||||
|
||||
// Find EXE base in process memory
|
||||
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *) pbModule;
|
||||
IMAGE_NT_HEADERS *inh = (IMAGE_NT_HEADERS *) (pbModule + idh->e_lfanew);
|
||||
|
||||
// Search through import table if it exists and replace the target DLL with our DLL filename
|
||||
PIMAGE_SECTION_HEADER pRemoteSectionHeaders
|
||||
= (PIMAGE_SECTION_HEADER)((PBYTE)pbModule
|
||||
+ sizeof(inh->Signature)
|
||||
+ sizeof(inh->FileHeader)
|
||||
+ inh->FileHeader.SizeOfOptionalHeader);
|
||||
size_t total_size = inh->OptionalHeader.SizeOfHeaders;
|
||||
|
||||
for (DWORD n = 0; n < inh->FileHeader.NumberOfSections; ++n) {
|
||||
IMAGE_SECTION_HEADER *header = (IMAGE_SECTION_HEADER *)(pRemoteSectionHeaders + n);
|
||||
size_t new_total_size = header->VirtualAddress + header->Misc.VirtualSize;
|
||||
if (new_total_size > total_size)
|
||||
total_size = new_total_size;
|
||||
}
|
||||
|
||||
void *remote_addr = NULL;
|
||||
size_t remote_addr_ptr = 0;
|
||||
|
||||
for (size_t i = 0; i < 10000 && remote_addr == NULL; i++) {
|
||||
remote_addr = VirtualAlloc(
|
||||
pbModule + total_size + (MM_ALLOCATION_GRANULARITY * (i + 1)),
|
||||
(MAX_PATH + 1) * iat_hook_dlls->nitems,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
}
|
||||
|
||||
log_assert(remote_addr != NULL);
|
||||
|
||||
if (inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0) {
|
||||
PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule
|
||||
+ inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
DWORD size = 0;
|
||||
while (inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0
|
||||
|| size < inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) {
|
||||
IMAGE_IMPORT_DESCRIPTOR *ImageImport = (IMAGE_IMPORT_DESCRIPTOR *)pImageImport;
|
||||
|
||||
if (ImageImport->Name == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const char *name = (const char *)(pbModule + ImageImport->Name);
|
||||
|
||||
for (size_t i = 0; i < iat_hook_dlls->nitems; i++) {
|
||||
const char *iat_hook_dll =
|
||||
*array_item(char *, iat_hook_dlls, i);
|
||||
|
||||
char *iat_hook_replacement = strstr(iat_hook_dll, "=");
|
||||
|
||||
if (!iat_hook_replacement)
|
||||
continue;
|
||||
|
||||
*iat_hook_replacement = '\0';
|
||||
|
||||
const char *expected_dll = iat_hook_dll;
|
||||
const char *replacement_path_dll = iat_hook_replacement + 1;
|
||||
|
||||
if (strcmp(name, expected_dll) == 0) {
|
||||
pe_patch((PBYTE)remote_addr + remote_addr_ptr, replacement_path_dll, strlen(replacement_path_dll));
|
||||
|
||||
log_misc("Replacing %s with %s", name, replacement_path_dll);
|
||||
|
||||
DWORD val = (DWORD)((PBYTE)remote_addr - pbModule);
|
||||
pe_patch(&ImageImport->Name, &val, sizeof(DWORD));
|
||||
pe_patch(pImageImport, &ImageImport, sizeof(ImageImport));
|
||||
|
||||
remote_addr_ptr += strlen(replacement_path_dll) + 1;
|
||||
}
|
||||
|
||||
*iat_hook_replacement = '=';
|
||||
}
|
||||
|
||||
pImageImport++;
|
||||
size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
}
|
||||
} else {
|
||||
log_misc("Couldn't find import table, can't hook DLL\n");
|
||||
goto inject_fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
inject_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
void module_context_init(struct module_context *module, const char *path)
|
||||
{
|
||||
log_assert(module != NULL);
|
||||
log_assert(path != NULL);
|
||||
|
||||
module->dll = LoadLibrary(path);
|
||||
|
||||
if (module->dll == NULL) {
|
||||
LPSTR buffer;
|
||||
DWORD err = GetLastError();
|
||||
|
||||
FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &buffer,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (err == ERROR_MOD_NOT_FOUND) {
|
||||
log_warning("%s is likely missing dependencies", path);
|
||||
log_warning("Do you have vcredist/directx runtimes installed?");
|
||||
}
|
||||
|
||||
log_fatal("%s: Failed to load game DLL: %s", path, buffer);
|
||||
|
||||
LocalFree(buffer);
|
||||
}
|
||||
|
||||
module->path = str_dup(path);
|
||||
}
|
||||
|
||||
|
||||
void module_context_init_with_iat_hooks(struct module_context *module, const char *path, struct array *iat_hook_dlls)
|
||||
{
|
||||
log_assert(module != NULL);
|
||||
log_assert(path != NULL);
|
||||
|
||||
module->dll = LoadLibraryExA(path, NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||
|
||||
if (module->dll == NULL) {
|
||||
LPSTR buffer;
|
||||
DWORD err = GetLastError();
|
||||
|
||||
FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &buffer,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (err == ERROR_MOD_NOT_FOUND) {
|
||||
log_warning("%s is likely missing dependencies", path);
|
||||
log_warning("Do you have vcredist/directx runtimes installed?");
|
||||
}
|
||||
|
||||
log_fatal("%s: Failed to load game DLL: %s", path, buffer);
|
||||
|
||||
LocalFree(buffer);
|
||||
}
|
||||
|
||||
// Add IAT hooks
|
||||
module_replace_dll_iat(module->dll, iat_hook_dlls);
|
||||
|
||||
log_misc("Finished processing IAT hooks");
|
||||
|
||||
// Resolve all imports like a normally loaded DLL
|
||||
pe_resolve_imports(module->dll);
|
||||
|
||||
dll_entry_t orig_entry = pe_get_entry_point(module->dll);
|
||||
orig_entry(module->dll, DLL_PROCESS_ATTACH, NULL);
|
||||
|
||||
log_misc("Finished resolving imports");
|
||||
|
||||
module->path = str_dup(path);
|
||||
}
|
||||
|
||||
bool module_context_invoke_init(
|
||||
const struct module_context *module,
|
||||
char *sidcode,
|
||||
struct property_node *app_config)
|
||||
{
|
||||
dll_entry_init_t init;
|
||||
|
||||
log_assert(module != NULL);
|
||||
log_assert(sidcode != NULL);
|
||||
log_assert(app_config != NULL);
|
||||
|
||||
init = (void *) GetProcAddress(module->dll, "dll_entry_init");
|
||||
|
||||
if (init == NULL) {
|
||||
log_fatal(
|
||||
"%s: dll_entry_init not found. Is this a game DLL?", module->path);
|
||||
}
|
||||
|
||||
return init(sidcode, app_config);
|
||||
}
|
||||
|
||||
bool module_context_invoke_main(const struct module_context *module)
|
||||
{
|
||||
/* GCC warns if you call a variable "main" */
|
||||
dll_entry_main_t main_;
|
||||
|
||||
log_assert(module != NULL);
|
||||
|
||||
main_ = (void *) GetProcAddress(module->dll, "dll_entry_main");
|
||||
|
||||
if (main_ == NULL) {
|
||||
log_fatal(
|
||||
"%s: dll_entry_main not found. Is this a game DLL?", module->path);
|
||||
}
|
||||
|
||||
return main_();
|
||||
}
|
||||
|
||||
void module_context_fini(struct module_context *module)
|
||||
{
|
||||
if (module == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(module->path);
|
||||
|
||||
if (module->dll != NULL) {
|
||||
FreeLibrary(module->dll);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "util/array.h"
|
||||
|
||||
struct module_context {
|
||||
HMODULE dll;
|
||||
char *path;
|
||||
};
|
||||
|
||||
void module_context_init(struct module_context *module, const char *path);
|
||||
void module_context_init_with_iat_hooks(struct module_context *module, const char *path, struct array *iat_hook_dlls);
|
||||
bool module_context_invoke_init(
|
||||
const struct module_context *module,
|
||||
char *sidcode,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "launcher/options.h"
|
||||
|
||||
#include "util/array.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
#define DEFAULT_HEAP_SIZE 16777216
|
||||
@@ -25,6 +26,7 @@ void options_init(struct options *options)
|
||||
options->remote_debugger = false;
|
||||
array_init(&options->hook_dlls);
|
||||
array_init(&options->before_hook_dlls);
|
||||
array_init(&options->iat_hook_dlls);
|
||||
|
||||
options->override_service = NULL;
|
||||
options->override_urlslash_enabled = false;
|
||||
@@ -131,6 +133,19 @@ bool options_read_cmdline(struct options *options, int argc, const char **argv)
|
||||
|
||||
break;
|
||||
|
||||
case 'I': {
|
||||
if (i + 1 >= argc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *dll = argv[++i];
|
||||
log_assert(strstr(dll, "=") != NULL);
|
||||
|
||||
*array_append(const char *, &options->iat_hook_dlls) = dll;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Y':
|
||||
if (i + 1 >= argc) {
|
||||
return false;
|
||||
@@ -218,6 +233,8 @@ void options_print_usage(void)
|
||||
"times)\n"
|
||||
" -B [filename] Load pre-hook DLL loaded before avs boot "
|
||||
"(can be specified multiple times)\n"
|
||||
" -I [filename] Load pre-hook DLL that overrides IAT reference before execution"
|
||||
"(can be specified multiple times)\n"
|
||||
" -Y [filename] Log to a file in addition to the console\n"
|
||||
" -D Halt the launcher before bootstrapping AVS "
|
||||
"until a"
|
||||
@@ -228,4 +245,5 @@ void options_fini(struct options *options)
|
||||
{
|
||||
array_fini(&options->hook_dlls);
|
||||
array_fini(&options->before_hook_dlls);
|
||||
array_fini(&options->iat_hook_dlls);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ struct options {
|
||||
const char *logfile;
|
||||
struct array hook_dlls;
|
||||
struct array before_hook_dlls;
|
||||
struct array iat_hook_dlls;
|
||||
bool remote_debugger;
|
||||
const char *override_service;
|
||||
bool override_urlslash_enabled;
|
||||
|
||||
15
src/main/popnhook-util/Module.mk
Normal file
15
src/main/popnhook-util/Module.mk
Normal file
@@ -0,0 +1,15 @@
|
||||
libs += popnhook-util
|
||||
|
||||
libs_popnhook-util := \
|
||||
iidxhook-util \
|
||||
ezusb-iidx-emu \
|
||||
ezusb2-popn-emu \
|
||||
ezusb2-emu \
|
||||
acioemu \
|
||||
hook \
|
||||
hooklib \
|
||||
util \
|
||||
|
||||
src_popnhook-util := \
|
||||
acio.c \
|
||||
mixer.c \
|
||||
115
src/main/popnhook-util/acio.c
Normal file
115
src/main/popnhook-util/acio.c
Normal file
@@ -0,0 +1,115 @@
|
||||
// clang-format off
|
||||
// Don't format because the order is important here
|
||||
#include <windows.h>
|
||||
#include <devioctl.h>
|
||||
#include <ntdef.h>
|
||||
#include <ntddser.h>
|
||||
// clang-format on
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "acioemu/addr.h"
|
||||
#include "acioemu/emu.h"
|
||||
#include "acioemu/icca.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
#include "hooklib/rs232.h"
|
||||
|
||||
#include "popnhook-util/acio.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/iobuf.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static struct ac_io_emu popnhook_acio_emu;
|
||||
static struct ac_io_emu_icca popnhook_acio_emu_icca;
|
||||
|
||||
static bool popnhook_icca_override_version;
|
||||
static enum ac_io_emu_icca_version popnhook_icca_override_version_value;
|
||||
|
||||
|
||||
void popnhook_acio_override_version(enum ac_io_emu_icca_version version)
|
||||
{
|
||||
popnhook_icca_override_version = true;
|
||||
popnhook_icca_override_version_value = version;
|
||||
}
|
||||
|
||||
void popnhook_acio_init(bool legacy_mode)
|
||||
{
|
||||
if (legacy_mode) {
|
||||
ac_io_legacy_mode();
|
||||
}
|
||||
|
||||
ac_io_emu_init(&popnhook_acio_emu, L"COM1");
|
||||
|
||||
ac_io_emu_icca_init(
|
||||
&popnhook_acio_emu_icca, &popnhook_acio_emu, 0);
|
||||
if (popnhook_icca_override_version) {
|
||||
ac_io_emu_icca_set_version(
|
||||
&popnhook_acio_emu_icca,
|
||||
popnhook_icca_override_version_value
|
||||
);
|
||||
}
|
||||
|
||||
rs232_hook_add_fd(popnhook_acio_emu.fd);
|
||||
}
|
||||
|
||||
void popnhook_acio_fini(void)
|
||||
{
|
||||
ac_io_emu_fini(&popnhook_acio_emu);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
popnhook_acio_dispatch_irp(struct irp *irp)
|
||||
{
|
||||
const struct ac_io_message *msg;
|
||||
HRESULT hr;
|
||||
|
||||
log_assert(irp != NULL);
|
||||
|
||||
if (!ac_io_emu_match_irp(&popnhook_acio_emu, irp)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
hr = ac_io_emu_dispatch_irp(&popnhook_acio_emu, irp);
|
||||
|
||||
if (hr != S_OK) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
msg = ac_io_emu_request_peek(&popnhook_acio_emu);
|
||||
|
||||
switch (msg->addr) {
|
||||
case 0:
|
||||
ac_io_emu_cmd_assign_addrs(&popnhook_acio_emu, msg, 1);
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ac_io_emu_icca_dispatch_request(
|
||||
&popnhook_acio_emu_icca, msg);
|
||||
|
||||
break;
|
||||
|
||||
case AC_IO_BROADCAST:
|
||||
log_warning("Broadcast(?) message on pop'n ACIO bus?");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning(
|
||||
"ACIO message on unhandled bus address: %d", msg->addr);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ac_io_emu_request_pop(&popnhook_acio_emu);
|
||||
}
|
||||
}
|
||||
33
src/main/popnhook-util/acio.h
Normal file
33
src/main/popnhook-util/acio.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef POPNHOOK_UTIL_ACIO_H
|
||||
#define POPNHOOK_UTIL_ACIO_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "acioemu/icca.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
/**
|
||||
* Initialize an emulated ACIO on COM1 for pop'n music.
|
||||
*
|
||||
* @param legacy_mode Set to true if running on slotted readers on pop'n 15-18.
|
||||
*/
|
||||
void popnhook_acio_init(bool legacy_mode);
|
||||
|
||||
/**
|
||||
* Use the specified ICCA emulation version
|
||||
*/
|
||||
void popnhook_acio_override_version(enum ac_io_emu_icca_version version);
|
||||
|
||||
/**
|
||||
* Cleanup the ACIO emulation layer.
|
||||
*/
|
||||
void popnhook_acio_fini(void);
|
||||
|
||||
/**
|
||||
* iohook dispatch function. Needs to be installed.
|
||||
*/
|
||||
HRESULT popnhook_acio_dispatch_irp(struct irp *irp);
|
||||
|
||||
#endif
|
||||
71
src/main/popnhook-util/mixer.c
Normal file
71
src/main/popnhook-util/mixer.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#define LOG_MODULE "jbhook-mixer"
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls);
|
||||
MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps);
|
||||
MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
|
||||
MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
|
||||
MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
|
||||
MMRESULT STDCALL hook_mixerClose(HMIXER hmx);
|
||||
MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo);
|
||||
|
||||
static const struct hook_symbol mixer_hook_syms[] = {
|
||||
{.name = "mixerGetLineControlsA",
|
||||
.patch = hook_mixerGetLineControlsA},
|
||||
{.name = "mixerGetDevCapsA",
|
||||
.patch = hook_mixerGetDevCapsA},
|
||||
{.name = "mixerOpen",
|
||||
.patch = hook_mixerOpen},
|
||||
{.name = "mixerSetControlDetails",
|
||||
.patch = hook_mixerSetControlDetails},
|
||||
{.name = "mixerGetControlDetailsA",
|
||||
.patch = hook_mixerGetControlDetailsA},
|
||||
{.name = "mixerClose",
|
||||
.patch = hook_mixerClose},
|
||||
{.name = "mixerGetLineInfoA",
|
||||
.patch = hook_mixerGetLineInfoA},
|
||||
};
|
||||
|
||||
MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen) {
|
||||
*(DWORD*)phmx = 1234; // any non-zero value is fine
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerClose(HMIXER hmx) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
void popnhook_mixer_hook_init(void)
|
||||
{
|
||||
hook_table_apply(NULL, "winmm.dll", mixer_hook_syms, lengthof(mixer_hook_syms));
|
||||
|
||||
log_info("Inserted mixer hooks");
|
||||
}
|
||||
11
src/main/popnhook-util/mixer.h
Normal file
11
src/main/popnhook-util/mixer.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef POPNHOOK_UTIL_MIXER_H
|
||||
#define POPNHOOK_UTIL_MIXER_H
|
||||
|
||||
/**
|
||||
* Hook some mixer related functions and stub out attempts to change the volume.
|
||||
* In addition to being annoying, this can fail on Vista+ on some outputs,
|
||||
* despite not actually preventing sound from playing.
|
||||
*/
|
||||
void popnhook_mixer_hook_init(void);
|
||||
|
||||
#endif
|
||||
34
src/main/popnhook1/Module.mk
Normal file
34
src/main/popnhook1/Module.mk
Normal file
@@ -0,0 +1,34 @@
|
||||
avsdlls += popnhook1
|
||||
|
||||
deplibs_popnhook1 := \
|
||||
avs \
|
||||
|
||||
ldflags_popnhook1 := \
|
||||
-lws2_32 \
|
||||
-liphlpapi \
|
||||
|
||||
libs_popnhook1 := \
|
||||
iidxhook-util \
|
||||
ezusb-iidx-emu \
|
||||
ezusb2-popn-emu \
|
||||
ezusb2-emu \
|
||||
security \
|
||||
acioemu \
|
||||
hook \
|
||||
hooklib \
|
||||
eamio \
|
||||
popnio \
|
||||
cconfig \
|
||||
util \
|
||||
ezusb \
|
||||
security \
|
||||
popnhook-util \
|
||||
|
||||
src_popnhook1 := \
|
||||
avs-boot.c \
|
||||
config-eamuse.c \
|
||||
config-gfx.c \
|
||||
config-sec.c \
|
||||
d3d9.c \
|
||||
dllmain.c \
|
||||
filesystem.c \
|
||||
115
src/main/popnhook1/avs-boot.c
Normal file
115
src/main/popnhook1/avs-boot.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#define LOG_MODULE "avs-boot"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "popnhook1/avs-boot.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static int (*real_ea3_boot_avs)(struct property_node *config);
|
||||
static int (*real_ea3_boot)(struct property_node *config);
|
||||
|
||||
static int my_ea3_boot_avs(struct property_node *config);
|
||||
static int my_ea3_boot(struct property_node *config);
|
||||
|
||||
static struct net_addr popnhook1_avs_boot_eamuse_server_addr;
|
||||
|
||||
static const struct hook_symbol popnhook1_avs_hook_syms[] = {
|
||||
{.name = "ea3_boot",
|
||||
.patch = my_ea3_boot_avs,
|
||||
.link = (void **) &real_ea3_boot_avs},
|
||||
};
|
||||
|
||||
static const struct hook_symbol popnhook1_ea3_hook_syms[] = {
|
||||
{.name = "ea3_boot",
|
||||
.patch = my_ea3_boot,
|
||||
.link = (void **) &real_ea3_boot},
|
||||
};
|
||||
|
||||
static void avs_boot_replace_property_str(
|
||||
struct property_node *node, const char *name, const char *val)
|
||||
{
|
||||
struct property_node *tmp;
|
||||
|
||||
tmp = property_search(NULL, node, name);
|
||||
|
||||
if (tmp) {
|
||||
property_node_remove(tmp);
|
||||
}
|
||||
|
||||
tmp = property_node_create(NULL, node, PROPERTY_TYPE_STR, name, val);
|
||||
|
||||
if (tmp) {
|
||||
property_node_datasize(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_eamuse_addr(struct property_node *config)
|
||||
{
|
||||
char *server_addr;
|
||||
|
||||
if (popnhook1_avs_boot_eamuse_server_addr.type != NET_ADDR_TYPE_INVALID) {
|
||||
log_misc("Injecting network server address");
|
||||
|
||||
server_addr = net_addr_to_str(&popnhook1_avs_boot_eamuse_server_addr);
|
||||
|
||||
avs_boot_replace_property_str(config, "network/services", server_addr);
|
||||
|
||||
free(server_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static int my_ea3_boot(struct property_node *config)
|
||||
{
|
||||
log_info("Called my_ea3_boot");
|
||||
insert_eamuse_addr(config);
|
||||
return real_ea3_boot(config);
|
||||
}
|
||||
|
||||
static int my_ea3_boot_avs(struct property_node *config)
|
||||
{
|
||||
log_info("Called my_ea3_boot_avs");
|
||||
insert_eamuse_addr(config);
|
||||
return real_ea3_boot_avs(config);
|
||||
}
|
||||
|
||||
void popnhook1_avs_boot_init()
|
||||
{
|
||||
// pop'n 15 has the ea3_boot in libavs-win32.dll
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"libavs-win32.dll",
|
||||
popnhook1_avs_hook_syms,
|
||||
lengthof(popnhook1_avs_hook_syms));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"libavs-win32-ea3.dll",
|
||||
popnhook1_ea3_hook_syms,
|
||||
lengthof(popnhook1_ea3_hook_syms));
|
||||
|
||||
memset(&popnhook1_avs_boot_eamuse_server_addr, 0, sizeof(struct net_addr));
|
||||
|
||||
log_info("Inserted avs log hooks");
|
||||
}
|
||||
|
||||
void popnhook1_avs_boot_set_eamuse_addr(const struct net_addr *server_addr)
|
||||
{
|
||||
char *str;
|
||||
|
||||
str = net_addr_to_str(server_addr);
|
||||
log_info("Setting eamuse server: %s", str);
|
||||
free(str);
|
||||
|
||||
memcpy(
|
||||
&popnhook1_avs_boot_eamuse_server_addr,
|
||||
server_addr,
|
||||
sizeof(struct net_addr));
|
||||
}
|
||||
19
src/main/popnhook1/avs-boot.h
Normal file
19
src/main/popnhook1/avs-boot.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef POPNHOOK1_AVS_BOOT_H
|
||||
#define POPNHOOK1_AVS_BOOT_H
|
||||
|
||||
#include "util/net.h"
|
||||
|
||||
/**
|
||||
* Initialize hooking of avs_boot and ea3_boot. This re-enables avs logging
|
||||
* and injects a few important settings.
|
||||
*/
|
||||
void popnhook1_avs_boot_init();
|
||||
|
||||
/**
|
||||
* Set the target eamuse server address.
|
||||
*
|
||||
* @param server_addr Address to target eamuse server.
|
||||
*/
|
||||
void popnhook1_avs_boot_set_eamuse_addr(const struct net_addr *server_addr);
|
||||
|
||||
#endif
|
||||
145
src/main/popnhook1/config-eamuse.c
Normal file
145
src/main/popnhook1/config-eamuse.c
Normal file
@@ -0,0 +1,145 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "popnhook1/config-eamuse.h"
|
||||
|
||||
#include "security/mcode.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_SERVER_KEY "eamuse.server"
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_PCBID_KEY "eamuse.pcbid"
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_EAMID_KEY "eamuse.eamid"
|
||||
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_DEFAULT_SERVER_VALUE "localhost:80"
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE security_id_default
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE_LEN \
|
||||
sizeof(security_id_default)
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE security_id_default
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE_LEN \
|
||||
sizeof(security_id_default)
|
||||
|
||||
const struct net_addr popnhook1_eamuse_default_server = {
|
||||
.type = NET_ADDR_TYPE_HOSTNAME,
|
||||
.hostname.host = "localhost",
|
||||
.hostname.port = 80,
|
||||
};
|
||||
|
||||
void popnhook1_config_eamuse_init(struct cconfig *config)
|
||||
{
|
||||
cconfig_util_set_str(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_EAMUSE_SERVER_KEY,
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_SERVER_VALUE,
|
||||
"URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 "
|
||||
"(e.g. 127.0.0.1:80) of the target eamuse server. The port is "
|
||||
"optional "
|
||||
"but defaults to 80.");
|
||||
|
||||
cconfig_util_set_data(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_EAMUSE_PCBID_KEY,
|
||||
(uint8_t *) &POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE,
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE_LEN,
|
||||
"PCBID");
|
||||
|
||||
cconfig_util_set_data(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_EAMUSE_EAMID_KEY,
|
||||
(uint8_t *) &POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE,
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE_LEN,
|
||||
"EAMID");
|
||||
}
|
||||
|
||||
void popnhook1_config_eamuse_get(
|
||||
struct popnhook1_config_eamuse *config_eamuse, struct cconfig *config)
|
||||
{
|
||||
char server_url[1024];
|
||||
char *tmp;
|
||||
char *tmp2;
|
||||
|
||||
memset(config_eamuse, 0, sizeof(struct popnhook1_config_eamuse));
|
||||
|
||||
if (!cconfig_util_get_str(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_EAMUSE_SERVER_KEY,
|
||||
server_url,
|
||||
sizeof(server_url),
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_SERVER_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%s'",
|
||||
POPNHOOK1_CONFIG_EAMUSE_SERVER_KEY,
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_SERVER_VALUE);
|
||||
}
|
||||
|
||||
if (!net_str_parse(server_url, &config_eamuse->server)) {
|
||||
memcpy(
|
||||
&config_eamuse->server,
|
||||
&popnhook1_eamuse_default_server,
|
||||
sizeof(config_eamuse->server));
|
||||
tmp = net_addr_to_str(&config_eamuse->server);
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default",
|
||||
tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_data(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_EAMUSE_PCBID_KEY,
|
||||
(uint8_t *) &config_eamuse->pcbid,
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE_LEN,
|
||||
(uint8_t *) &POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE)) {
|
||||
tmp = security_id_to_str(
|
||||
&POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE, false);
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default",
|
||||
tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
if (!security_id_verify(&config_eamuse->pcbid)) {
|
||||
tmp = security_id_to_str(
|
||||
&POPNHOOK1_CONFIG_EAMUSE_DEFAULT_PCBID_VALUE, false);
|
||||
tmp2 = security_id_to_str(&config_eamuse->pcbid, false);
|
||||
log_warning(
|
||||
"PCBID verification of '%s' failed, fallback to default "
|
||||
"PCBID '%s'",
|
||||
tmp2,
|
||||
tmp);
|
||||
free(tmp);
|
||||
free(tmp2);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_data(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_EAMUSE_EAMID_KEY,
|
||||
(uint8_t *) &config_eamuse->eamid,
|
||||
POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE_LEN,
|
||||
(uint8_t *) &POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE)) {
|
||||
tmp = security_id_to_str(
|
||||
&POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE, false);
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default",
|
||||
tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
if (!security_id_verify(&config_eamuse->eamid)) {
|
||||
tmp = security_id_to_str(
|
||||
&POPNHOOK1_CONFIG_EAMUSE_DEFAULT_EAMID_VALUE, false);
|
||||
tmp2 = security_id_to_str(&config_eamuse->eamid, false);
|
||||
log_warning(
|
||||
"EAMID verification of '%s' failed, fallback to default "
|
||||
"EAMID '%s'",
|
||||
tmp2,
|
||||
tmp);
|
||||
free(tmp);
|
||||
free(tmp2);
|
||||
}
|
||||
}
|
||||
21
src/main/popnhook1/config-eamuse.h
Normal file
21
src/main/popnhook1/config-eamuse.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef POPNHOOK1_CONFIG_EAMUSE_H
|
||||
#define POPNHOOK1_CONFIG_EAMUSE_H
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
#include "security/id.h"
|
||||
|
||||
#include "util/net.h"
|
||||
|
||||
struct popnhook1_config_eamuse {
|
||||
struct net_addr server;
|
||||
struct security_id pcbid;
|
||||
struct security_id eamid;
|
||||
};
|
||||
|
||||
void popnhook1_config_eamuse_init(struct cconfig *config);
|
||||
|
||||
void popnhook1_config_eamuse_get(
|
||||
struct popnhook1_config_eamuse *config_eamuse, struct cconfig *config);
|
||||
|
||||
#endif
|
||||
97
src/main/popnhook1/config-gfx.c
Normal file
97
src/main/popnhook1/config-gfx.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "popnhook1/config-gfx.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define POPNHOOK1_CONFIG_GFX_WINDOWED_KEY "gfx.windowed"
|
||||
#define POPNHOOK1_CONFIG_GFX_FRAMED_KEY "gfx.framed"
|
||||
#define POPNHOOK1_CONFIG_GFX_WINDOW_WIDTH_KEY "gfx.window_width"
|
||||
#define POPNHOOK1_CONFIG_GFX_WINDOW_HEIGHT_KEY "gfx.window_height"
|
||||
|
||||
|
||||
#define POPNHOOK1_CONFIG_GFX_DEFAULT_FRAMED_VALUE false
|
||||
#define POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE false
|
||||
#define POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE -1
|
||||
#define POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE -1
|
||||
|
||||
void popnhook1_config_gfx_init(struct cconfig *config)
|
||||
{
|
||||
cconfig_util_set_bool(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_WINDOWED_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE,
|
||||
"Run the game windowed");
|
||||
|
||||
cconfig_util_set_bool(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_FRAMED_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_FRAMED_VALUE,
|
||||
"Run the game in a framed window (requires windowed option)");
|
||||
|
||||
cconfig_util_set_int(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_WINDOW_WIDTH_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE,
|
||||
"Windowed width, -1 for default size");
|
||||
|
||||
cconfig_util_set_int(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_WINDOW_HEIGHT_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE,
|
||||
"Windowed height, -1 for default size");
|
||||
}
|
||||
|
||||
void popnhook1_config_gfx_get(
|
||||
struct popnhook1_config_gfx *config_gfx, struct cconfig *config)
|
||||
{
|
||||
if (!cconfig_util_get_bool(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_WINDOWED_KEY,
|
||||
&config_gfx->windowed,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
POPNHOOK1_CONFIG_GFX_WINDOWED_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_bool(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_FRAMED_KEY,
|
||||
&config_gfx->framed,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_FRAMED_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
POPNHOOK1_CONFIG_GFX_FRAMED_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_FRAMED_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_int(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_WINDOW_WIDTH_KEY,
|
||||
&config_gfx->window_width,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
POPNHOOK1_CONFIG_GFX_WINDOW_WIDTH_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_int(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_GFX_WINDOW_HEIGHT_KEY,
|
||||
&config_gfx->window_height,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
POPNHOOK1_CONFIG_GFX_WINDOW_HEIGHT_KEY,
|
||||
POPNHOOK1_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE);
|
||||
}
|
||||
}
|
||||
21
src/main/popnhook1/config-gfx.h
Normal file
21
src/main/popnhook1/config-gfx.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef POPNHOOK1_CONFIG_GFX_H
|
||||
#define POPNHOOK1_CONFIG_GFX_H
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
#include "popnhook1/d3d9.h"
|
||||
|
||||
// see struct popnhook1_d3d9_config for more info
|
||||
struct popnhook1_config_gfx {
|
||||
bool framed;
|
||||
bool windowed;
|
||||
int32_t window_width;
|
||||
int32_t window_height;
|
||||
};
|
||||
|
||||
void popnhook1_config_gfx_init(struct cconfig *config);
|
||||
|
||||
void popnhook1_config_gfx_get(
|
||||
struct popnhook1_config_gfx *config_gfx, struct cconfig *config);
|
||||
|
||||
#endif
|
||||
80
src/main/popnhook1/config-sec.c
Normal file
80
src/main/popnhook1/config-sec.c
Normal file
@@ -0,0 +1,80 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "popnhook1/config-sec.h"
|
||||
|
||||
#include "security/mcode.h"
|
||||
#include "security/rp.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
#define POPNHOOK1_CONFIG_SEC_BLACK_PLUG_MCODE_KEY "sec.black_plug_mcode"
|
||||
|
||||
#define POPNHOOK1_CONFIG_SEC_DEFAULT_BLACK_PLUG_MCODE_VALUE \
|
||||
popnhook1_security_default_black_plug_mcode
|
||||
|
||||
static const struct security_mcode popnhook1_security_default_black_plug_mcode =
|
||||
{
|
||||
.header = SECURITY_MCODE_HEADER,
|
||||
.unkn = SECURITY_MCODE_UNKN_Q,
|
||||
.game = SECURITY_MCODE_GAME_POPN_15,
|
||||
.region = SECURITY_MCODE_REGION_JAPAN,
|
||||
.cabinet = SECURITY_MCODE_CABINET_A,
|
||||
.revision = SECURITY_MCODE_REVISION_A,
|
||||
};
|
||||
|
||||
void popnhook1_config_sec_init(struct cconfig *config)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
tmp = security_mcode_to_str(
|
||||
&POPNHOOK1_CONFIG_SEC_DEFAULT_BLACK_PLUG_MCODE_VALUE);
|
||||
|
||||
cconfig_util_set_str(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_SEC_BLACK_PLUG_MCODE_KEY,
|
||||
tmp,
|
||||
"Security black plug mcode id string (e.g. GQC02JAA).");
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
void popnhook1_config_sec_get(
|
||||
struct popnhook1_config_sec *config_sec, struct cconfig *config)
|
||||
{
|
||||
char tmp_mcode[sizeof(struct security_mcode) + 1];
|
||||
char *tmp_str;
|
||||
|
||||
tmp_str = security_mcode_to_str(
|
||||
&POPNHOOK1_CONFIG_SEC_DEFAULT_BLACK_PLUG_MCODE_VALUE);
|
||||
|
||||
if (!cconfig_util_get_str(
|
||||
config,
|
||||
POPNHOOK1_CONFIG_SEC_BLACK_PLUG_MCODE_KEY,
|
||||
tmp_mcode,
|
||||
sizeof(tmp_mcode) - 1,
|
||||
tmp_str)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%s'",
|
||||
POPNHOOK1_CONFIG_SEC_BLACK_PLUG_MCODE_KEY,
|
||||
tmp_str);
|
||||
}
|
||||
|
||||
if (!security_mcode_parse(tmp_mcode, &config_sec->black_plug_mcode)) {
|
||||
log_warning(
|
||||
"Invalid format for value of key '%s' specified, fallback "
|
||||
"to default '%s'",
|
||||
POPNHOOK1_CONFIG_SEC_BLACK_PLUG_MCODE_KEY,
|
||||
tmp_str);
|
||||
memcpy(
|
||||
&config_sec->black_plug_mcode,
|
||||
&POPNHOOK1_CONFIG_SEC_DEFAULT_BLACK_PLUG_MCODE_VALUE,
|
||||
sizeof(POPNHOOK1_CONFIG_SEC_DEFAULT_BLACK_PLUG_MCODE_VALUE));
|
||||
}
|
||||
|
||||
free(tmp_str);
|
||||
}
|
||||
17
src/main/popnhook1/config-sec.h
Normal file
17
src/main/popnhook1/config-sec.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef POPNHOOK1_CONFIG_SEC_H
|
||||
#define POPNHOOK1_CONFIG_SEC_H
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
#include "security/mcode.h"
|
||||
|
||||
struct popnhook1_config_sec {
|
||||
struct security_mcode black_plug_mcode;
|
||||
};
|
||||
|
||||
void popnhook1_config_sec_init(struct cconfig *config);
|
||||
|
||||
void popnhook1_config_sec_get(
|
||||
struct popnhook1_config_sec *config_sec, struct cconfig *config);
|
||||
|
||||
#endif
|
||||
244
src/main/popnhook1/d3d9.c
Normal file
244
src/main/popnhook1/d3d9.c
Normal file
@@ -0,0 +1,244 @@
|
||||
#define LOG_MODULE "d3d9-hook"
|
||||
|
||||
#include <d3d9.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hook/com-proxy.h"
|
||||
#include "hook/pe.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "popnhook1/d3d9.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
|
||||
#include "hook/d3d9.h"
|
||||
|
||||
static struct popnhook1_d3d9_config popnhook1_d3d9_config;
|
||||
|
||||
HRESULT popnhook1_d3d9_irp_handler(struct hook_d3d9_irp *irp);
|
||||
|
||||
static const hook_d3d9_irp_handler_t popnhook1_d3d9_handlers[] = {
|
||||
popnhook1_d3d9_irp_handler,
|
||||
};
|
||||
|
||||
static void popnhook1_d3d9_validate_config(
|
||||
const struct popnhook1_d3d9_config *config)
|
||||
{
|
||||
if (!config->windowed && config->framed) {
|
||||
log_warning("Option framed does not have an effect without windowed");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
popnhook1_d3d9_log_config(const struct popnhook1_d3d9_config *config)
|
||||
{
|
||||
log_misc(
|
||||
"popnhook1_d3d9_config\n"
|
||||
"windowed: %d\n"
|
||||
"framed: %d\n"
|
||||
"override_window_width: %d\n"
|
||||
"override_window_height: %d\n"
|
||||
"texture_usage_fix: %d",
|
||||
config->windowed,
|
||||
config->framed,
|
||||
config->override_window_width,
|
||||
config->override_window_height,
|
||||
config->texture_usage_fix);
|
||||
}
|
||||
|
||||
void popnhook1_d3d9_init_config(struct popnhook1_d3d9_config *config)
|
||||
{
|
||||
config->windowed = false;
|
||||
config->framed = false;
|
||||
config->override_window_width = 0;
|
||||
config->override_window_height = 0;
|
||||
config->texture_usage_fix = false;
|
||||
}
|
||||
|
||||
void popnhook1_d3d9_configure(
|
||||
const struct popnhook1_d3d9_config *config)
|
||||
{
|
||||
log_assert(config);
|
||||
|
||||
popnhook1_d3d9_log_config(config);
|
||||
popnhook1_d3d9_validate_config(config);
|
||||
|
||||
memcpy(
|
||||
&popnhook1_d3d9_config,
|
||||
config,
|
||||
sizeof(struct popnhook1_d3d9_config));
|
||||
}
|
||||
|
||||
static void
|
||||
popnhook1_d3d9_fix_texture_usage(struct hook_d3d9_irp *irp)
|
||||
{
|
||||
log_assert(irp);
|
||||
log_assert(irp->op == HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE);
|
||||
|
||||
// TODO: Illegal to set render target 0 to NULL???
|
||||
irp->args.dev_create_texture.usage = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
popnhook1_d3d9_patch_window(struct hook_d3d9_irp *irp)
|
||||
{
|
||||
log_assert(irp);
|
||||
log_assert(irp->op == HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX);
|
||||
|
||||
if (popnhook1_d3d9_config.windowed &&
|
||||
popnhook1_d3d9_config.framed) {
|
||||
/* use a different style */
|
||||
irp->args.create_window_ex.style |= WS_OVERLAPPEDWINDOW;
|
||||
|
||||
/* also show mouse cursor */
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
|
||||
if (popnhook1_d3d9_config.override_window_width > 0 &&
|
||||
popnhook1_d3d9_config.override_window_height) {
|
||||
log_misc(
|
||||
"Overriding window size from %dx%d with %dx%d",
|
||||
irp->args.create_window_ex.width,
|
||||
irp->args.create_window_ex.height,
|
||||
popnhook1_d3d9_config.override_window_width,
|
||||
popnhook1_d3d9_config.override_window_height);
|
||||
|
||||
irp->args.create_window_ex.width =
|
||||
popnhook1_d3d9_config.override_window_width;
|
||||
irp->args.create_window_ex.height =
|
||||
popnhook1_d3d9_config.override_window_height;
|
||||
}
|
||||
}
|
||||
|
||||
static void popnhook1_d3d9_calc_win_size_with_framed(
|
||||
HWND hwnd, DWORD x, DWORD y, DWORD width, DWORD height, LPWINDOWPOS wp)
|
||||
{
|
||||
/* taken from dxwnd */
|
||||
RECT rect;
|
||||
DWORD style;
|
||||
int max_x, max_y;
|
||||
HMENU menu;
|
||||
|
||||
rect.left = x;
|
||||
rect.top = y;
|
||||
max_x = width;
|
||||
max_y = height;
|
||||
rect.right = x + max_x;
|
||||
rect.bottom = y + max_y;
|
||||
|
||||
style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
menu = GetMenu(hwnd);
|
||||
AdjustWindowRect(&rect, style, (menu != NULL));
|
||||
|
||||
/* shift down-right so that the border is visible
|
||||
and also update the iPosX,iPosY upper-left coordinates
|
||||
of the client area */
|
||||
|
||||
if (rect.left < 0) {
|
||||
rect.right -= rect.left;
|
||||
rect.left = 0;
|
||||
}
|
||||
|
||||
if (rect.top < 0) {
|
||||
rect.bottom -= rect.top;
|
||||
rect.top = 0;
|
||||
}
|
||||
|
||||
wp->x = rect.left;
|
||||
wp->y = rect.top;
|
||||
wp->cx = rect.right - rect.left;
|
||||
wp->cy = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
static void
|
||||
popnhook1_d3d9_fix_window_size_and_pos(struct hook_d3d9_irp *irp)
|
||||
{
|
||||
log_assert(irp);
|
||||
log_assert(irp->op == HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX);
|
||||
|
||||
if (popnhook1_d3d9_config.windowed &&
|
||||
popnhook1_d3d9_config.framed) {
|
||||
/* we have to adjust the window size, because the window needs to be a
|
||||
slightly bigger than the rendering resolution (window caption and
|
||||
stuff is included in the window size) */
|
||||
WINDOWPOS wp;
|
||||
|
||||
popnhook1_d3d9_calc_win_size_with_framed(
|
||||
irp->args.create_window_ex.result,
|
||||
irp->args.create_window_ex.x == CW_USEDEFAULT ? 0 : irp->args.create_window_ex.x,
|
||||
irp->args.create_window_ex.y == CW_USEDEFAULT ? 0 : irp->args.create_window_ex.y,
|
||||
irp->args.create_window_ex.width,
|
||||
irp->args.create_window_ex.height,
|
||||
&wp);
|
||||
|
||||
SetWindowPos(
|
||||
irp->args.create_window_ex.result, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
|
||||
|
||||
irp->args.create_window_ex.x = wp.x;
|
||||
irp->args.create_window_ex.y = wp.y;
|
||||
irp->args.create_window_ex.width = wp.cx;
|
||||
irp->args.create_window_ex.height = wp.cy;
|
||||
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void popnhook1_d3d9_fix_create_device_apply_window_mode(
|
||||
struct hook_d3d9_irp *irp)
|
||||
{
|
||||
log_assert(irp);
|
||||
log_assert(irp->op == HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE);
|
||||
D3DPRESENT_PARAMETERS *pp = irp->args.ctx_create_device.pp;
|
||||
|
||||
if (popnhook1_d3d9_config.windowed) {
|
||||
pp->Windowed = TRUE;
|
||||
pp->FullScreen_RefreshRateInHz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
popnhook1_d3d9_irp_handler(struct hook_d3d9_irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
log_assert(irp);
|
||||
|
||||
switch (irp->op) {
|
||||
case HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX:
|
||||
popnhook1_d3d9_patch_window(irp);
|
||||
|
||||
hr = hook_d3d9_irp_invoke_next(irp);
|
||||
|
||||
if (hr == S_OK) {
|
||||
popnhook1_d3d9_fix_window_size_and_pos(irp);
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
||||
case HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE:
|
||||
if (popnhook1_d3d9_config.texture_usage_fix)
|
||||
popnhook1_d3d9_fix_texture_usage(irp);
|
||||
|
||||
return hook_d3d9_irp_invoke_next(irp);
|
||||
|
||||
case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE:
|
||||
popnhook1_d3d9_fix_create_device_apply_window_mode(irp);
|
||||
|
||||
return hook_d3d9_irp_invoke_next(irp);
|
||||
|
||||
default:
|
||||
return hook_d3d9_irp_invoke_next(irp);
|
||||
}
|
||||
|
||||
log_fatal("Illegal state");
|
||||
}
|
||||
|
||||
void popnhook1_d3d9_init(void)
|
||||
{
|
||||
popnhook1_d3d9_init_config(&popnhook1_d3d9_config);
|
||||
|
||||
hook_d3d9_init(popnhook1_d3d9_handlers, lengthof(popnhook1_d3d9_handlers));
|
||||
}
|
||||
41
src/main/popnhook1/d3d9.h
Normal file
41
src/main/popnhook1/d3d9.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef POPNHOOK1_D3D9_H
|
||||
#define POPNHOOK1_D3D9_H
|
||||
|
||||
/**
|
||||
* Config structure for this module. Enable/disable supported features.
|
||||
*/
|
||||
struct popnhook1_d3d9_config {
|
||||
/**
|
||||
* Enable/disable window mode. Consider combining with framed.
|
||||
*/
|
||||
bool windowed;
|
||||
|
||||
/**
|
||||
* Enable a window frame and make the window movable, resizable, minizable.
|
||||
*/
|
||||
bool framed;
|
||||
|
||||
/**
|
||||
* Override the default window height which is determined by the frame
|
||||
* buffer size. Set this to 0 to disable the override.
|
||||
*/
|
||||
uint16_t override_window_width;
|
||||
|
||||
/**
|
||||
* Override the default window width which is determined by the frame buffer
|
||||
* size. Set this to 0 to disable the override.
|
||||
*/
|
||||
uint16_t override_window_height;
|
||||
|
||||
/**
|
||||
* Fix an issue with CreateTexture on later versions of Windows that prevents
|
||||
* the games from launching.
|
||||
*/
|
||||
bool texture_usage_fix;
|
||||
};
|
||||
|
||||
void popnhook1_d3d9_init(void);
|
||||
void popnhook1_d3d9_init_config(struct popnhook1_d3d9_config *config);
|
||||
void popnhook1_d3d9_configure(const struct popnhook1_d3d9_config *config);
|
||||
|
||||
#endif
|
||||
198
src/main/popnhook1/dllmain.c
Normal file
198
src/main/popnhook1/dllmain.c
Normal file
@@ -0,0 +1,198 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
#include "bemanitools/popnio.h"
|
||||
|
||||
#include "cconfig/cconfig-hook.h"
|
||||
|
||||
#include "ezusb-iidx-emu/node-security-plug.h"
|
||||
#include "ezusb-iidx-emu/nodes.h"
|
||||
|
||||
#include "hook/d3d9.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/adapter.h"
|
||||
|
||||
#include "popnhook1/avs-boot.h"
|
||||
#include "popnhook1/config-eamuse.h"
|
||||
#include "popnhook1/config-gfx.h"
|
||||
#include "popnhook1/config-sec.h"
|
||||
#include "popnhook1/d3d9.h"
|
||||
#include "popnhook1/filesystem.h"
|
||||
|
||||
#include "popnhook-util/acio.h"
|
||||
#include "popnhook-util/mixer.h"
|
||||
|
||||
#include "util/cmdline.h"
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
#include "ezusb2-emu/desc.h"
|
||||
#include "ezusb2-emu/device.h"
|
||||
|
||||
#include "iidxhook-util/acio.h"
|
||||
|
||||
#include "ezusb2-popn-emu/msg.h"
|
||||
|
||||
#include "hooklib/rs232.h"
|
||||
|
||||
#include "security/rp-sign-key.h"
|
||||
|
||||
#define POPNHOOK1_INFO_HEADER \
|
||||
"popnhook1 for pop'n music 15, 16, 17, 18" \
|
||||
", build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV)
|
||||
#define POPNHOOK1_CMD_USAGE \
|
||||
"Usage: inject.exe popnhook1.dll <popn.exe> [options...]"
|
||||
|
||||
static DWORD STDCALL my_GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo);
|
||||
static DWORD(STDCALL *real_GetStartupInfoA)(LPSTARTUPINFOA lpStartupInfo);
|
||||
|
||||
static bool popnhook1_init_check;
|
||||
|
||||
static const struct hook_symbol init_hook_syms[] = {
|
||||
{
|
||||
.name = "GetStartupInfoA",
|
||||
.patch = my_GetStartupInfoA,
|
||||
.link = (void **) &real_GetStartupInfoA,
|
||||
},
|
||||
};
|
||||
|
||||
static void popnhook_setup_d3d9_hooks(
|
||||
const struct popnhook1_config_gfx *config_gfx,
|
||||
const bool texture_usage_fix)
|
||||
{
|
||||
struct popnhook1_d3d9_config d3d9_config;
|
||||
|
||||
popnhook1_d3d9_init_config(&d3d9_config);
|
||||
|
||||
d3d9_config.windowed = config_gfx->windowed;
|
||||
d3d9_config.framed = config_gfx->framed;
|
||||
d3d9_config.override_window_width = config_gfx->window_width;
|
||||
d3d9_config.override_window_height = config_gfx->window_height;
|
||||
d3d9_config.texture_usage_fix = texture_usage_fix;
|
||||
|
||||
popnhook1_d3d9_init();
|
||||
popnhook1_d3d9_configure(&d3d9_config);
|
||||
}
|
||||
|
||||
static DWORD STDCALL my_GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
|
||||
{
|
||||
struct cconfig *config;
|
||||
|
||||
struct popnhook1_config_eamuse config_eamuse;
|
||||
struct popnhook1_config_gfx config_gfx;
|
||||
struct popnhook1_config_sec config_sec;
|
||||
|
||||
if (popnhook1_init_check)
|
||||
goto skip;
|
||||
|
||||
popnhook1_init_check = true;
|
||||
|
||||
log_info("-------------------------------------------------------------");
|
||||
log_info("----------------- Start popnhook1 hook init -----------------");
|
||||
log_info("-------------------------------------------------------------");
|
||||
|
||||
config = cconfig_init();
|
||||
|
||||
popnhook1_config_eamuse_init(config);
|
||||
popnhook1_config_gfx_init(config);
|
||||
popnhook1_config_sec_init(config);
|
||||
|
||||
if (!cconfig_hook_config_init(
|
||||
config,
|
||||
POPNHOOK1_INFO_HEADER "\n" POPNHOOK1_CMD_USAGE,
|
||||
CCONFIG_CMD_USAGE_OUT_DBG)) {
|
||||
cconfig_finit(config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
popnhook1_config_gfx_get(&config_gfx, config);
|
||||
popnhook1_config_eamuse_get(&config_eamuse, config);
|
||||
popnhook1_config_sec_get(&config_sec, config);
|
||||
|
||||
cconfig_finit(config);
|
||||
|
||||
popnhook_setup_d3d9_hooks(
|
||||
&config_gfx,
|
||||
// pop'n music 16 requires a patch for the texture usage to not crash on newer Windows
|
||||
memcmp(config_sec.black_plug_mcode.game, SECURITY_MCODE_GAME_POPN_16, sizeof(config_sec.black_plug_mcode.game)) == 0
|
||||
);
|
||||
|
||||
popnhook1_avs_boot_init();
|
||||
popnhook1_avs_boot_set_eamuse_addr(&config_eamuse.server);
|
||||
|
||||
/* Round plug security */
|
||||
|
||||
ezusb_iidx_emu_node_security_plug_set_plug_black_mcode(
|
||||
&config_sec.black_plug_mcode);
|
||||
ezusb_iidx_emu_node_security_plug_set_plug_white_mcode(
|
||||
&security_mcode_eamuse);
|
||||
ezusb_iidx_emu_node_security_plug_set_plug_black_sign_key(
|
||||
&security_rp_sign_key_black_popn);
|
||||
ezusb_iidx_emu_node_security_plug_set_plug_white_sign_key(
|
||||
&security_rp_sign_key_white_eamuse);
|
||||
|
||||
ezusb_iidx_emu_node_security_plug_set_pcbid(&config_eamuse.pcbid);
|
||||
ezusb_iidx_emu_node_security_plug_set_eamid(&config_eamuse.eamid);
|
||||
|
||||
/* Start up POPNIO.DLL */
|
||||
|
||||
log_info("Starting pop'n IO backend");
|
||||
popn_io_set_loggers(
|
||||
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
|
||||
|
||||
if (!popn_io_init(thread_create, thread_join, thread_destroy)) {
|
||||
log_fatal("Initializing pop'n IO backend failed");
|
||||
}
|
||||
|
||||
/* Start up EAMIO.DLL */
|
||||
|
||||
log_misc("Initializing card reader backend");
|
||||
eam_io_set_loggers(
|
||||
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
|
||||
|
||||
if (!eam_io_init(thread_create, thread_join, thread_destroy)) {
|
||||
log_fatal("Initializing card reader backend failed");
|
||||
}
|
||||
|
||||
iohook_push_handler(ezusb2_emu_device_dispatch_irp);
|
||||
iohook_push_handler(popnhook_acio_dispatch_irp);
|
||||
|
||||
hook_setupapi_init(&ezusb2_emu_desc_device.setupapi);
|
||||
ezusb2_emu_device_hook_init(ezusb2_popn_emu_msg_init());
|
||||
|
||||
rs232_hook_init();
|
||||
|
||||
popnhook_acio_init(true);
|
||||
|
||||
adapter_hook_init();
|
||||
filesystem_init();
|
||||
popnhook_mixer_hook_init();
|
||||
|
||||
log_info("-------------------------------------------------------------");
|
||||
log_info("------------------ End popnhook1 hook init ------------------");
|
||||
log_info("-------------------------------------------------------------");
|
||||
|
||||
skip:
|
||||
return real_GetStartupInfoA(lpStartupInfo);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE self, DWORD reason, void *ctx)
|
||||
{
|
||||
if (reason != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
log_to_writer(log_writer_debug, NULL);
|
||||
|
||||
hook_table_apply(
|
||||
NULL, "kernel32.dll", init_hook_syms, lengthof(init_hook_syms));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
148
src/main/popnhook1/filesystem.c
Normal file
148
src/main/popnhook1/filesystem.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#define LOG_MODULE "filesystem-hook"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/mem.h"
|
||||
#include "util/str.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static HANDLE STDCALL my_CreateFileA(
|
||||
LPCSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
static HANDLE STDCALL my_FindFirstFileA(
|
||||
LPCSTR lpFileName,
|
||||
LPWIN32_FIND_DATAA lpFindFileData);
|
||||
|
||||
static HANDLE(STDCALL *real_CreateFileA)(
|
||||
LPCSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
static HANDLE(STDCALL *real_FindFirstFileA)(
|
||||
LPCSTR lpFileName,
|
||||
LPWIN32_FIND_DATAA lpFindFileData);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static const struct hook_symbol settings_hook_syms[] = {
|
||||
{.name = "CreateFileA",
|
||||
.patch = my_CreateFileA,
|
||||
.link = (void **) &real_CreateFileA},
|
||||
{.name = "FindFirstFileA",
|
||||
.patch = my_FindFirstFileA,
|
||||
.link = (void **) &real_FindFirstFileA},
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static char *popnhook1_filesystem_get_path(LPCSTR lpFileName)
|
||||
{
|
||||
if (lpFileName != NULL && (tolower(lpFileName[0]) == 'd' || tolower(lpFileName[0]) == 'e') && lpFileName[1] == ':') {
|
||||
char *new_path = (char*)xmalloc(MAX_PATH);
|
||||
|
||||
char *data_ptr = strstr(lpFileName, "\\data\\");
|
||||
if (data_ptr == NULL)
|
||||
data_ptr = strstr(lpFileName, "\\prog\\");
|
||||
|
||||
if (data_ptr != NULL) {
|
||||
// Fix a data path string
|
||||
strcpy(new_path, "..\\..");
|
||||
strcat(new_path, data_ptr);
|
||||
} else {
|
||||
strcpy(new_path, lpFileName);
|
||||
new_path[1] = '\\';
|
||||
}
|
||||
|
||||
return new_path;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HANDLE STDCALL my_CreateFileA(
|
||||
LPCSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile)
|
||||
{
|
||||
char *new_path = popnhook1_filesystem_get_path(lpFileName);
|
||||
|
||||
if (new_path != NULL) {
|
||||
// log_misc("Remapped settings path %s -> %s", lpFileName, new_path);
|
||||
|
||||
return real_CreateFileA(
|
||||
new_path,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
lpSecurityAttributes,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
hTemplateFile);
|
||||
}
|
||||
|
||||
HANDLE status = real_CreateFileA(
|
||||
lpFileName,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
lpSecurityAttributes,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
hTemplateFile);
|
||||
|
||||
if (status == NULL) {
|
||||
log_warning("Could not open %s\n", lpFileName);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static HANDLE STDCALL my_FindFirstFileA(
|
||||
LPCSTR lpFileName,
|
||||
LPWIN32_FIND_DATAA lpFindFileData)
|
||||
{
|
||||
// pop'n 15 makes use of FindFirstFileA
|
||||
char *new_path = popnhook1_filesystem_get_path(lpFileName);
|
||||
|
||||
if (new_path != NULL) {
|
||||
// log_misc("Remapped settings path 2 %s -> %s", lpFileName, new_path);
|
||||
|
||||
return real_FindFirstFileA(
|
||||
new_path,
|
||||
lpFindFileData);
|
||||
}
|
||||
|
||||
return real_FindFirstFileA(
|
||||
lpFileName,
|
||||
lpFindFileData);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void filesystem_init(void)
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL, "kernel32.dll", settings_hook_syms, lengthof(settings_hook_syms));
|
||||
|
||||
log_info("Inserted filesystem hooks");
|
||||
}
|
||||
6
src/main/popnhook1/filesystem.h
Normal file
6
src/main/popnhook1/filesystem.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef POPNHOOK1_FILESYSTEM_H
|
||||
#define POPNHOOK1_FILESYSTEM_H
|
||||
|
||||
void filesystem_init(void);
|
||||
|
||||
#endif
|
||||
4
src/main/popnhook1/popnhook1.def
Normal file
4
src/main/popnhook1/popnhook1.def
Normal file
@@ -0,0 +1,4 @@
|
||||
LIBRARY popnhook1
|
||||
|
||||
EXPORTS
|
||||
DllMain@12 @1 NONAME
|
||||
10
src/main/popnio/Module.mk
Normal file
10
src/main/popnio/Module.mk
Normal file
@@ -0,0 +1,10 @@
|
||||
dlls += popnio
|
||||
|
||||
ldflags_popnio := \
|
||||
-lwinmm
|
||||
|
||||
libs_popnio := \
|
||||
geninput \
|
||||
|
||||
src_popnio := \
|
||||
popnio.c \
|
||||
76
src/main/popnio/popnio.c
Normal file
76
src/main/popnio/popnio.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bemanitools/popnio.h"
|
||||
#include "bemanitools/input.h"
|
||||
|
||||
void popn_io_set_loggers(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal)
|
||||
{
|
||||
input_set_loggers(misc, info, warning, fatal);
|
||||
}
|
||||
|
||||
bool popn_io_init(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy)
|
||||
{
|
||||
input_init(thread_create, thread_join, thread_destroy);
|
||||
mapper_config_load("pnm");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void popn_io_fini(void)
|
||||
{
|
||||
input_fini();
|
||||
}
|
||||
|
||||
uint32_t popn_io_get_buttons(void)
|
||||
{
|
||||
return (uint32_t) mapper_update();
|
||||
}
|
||||
|
||||
void popn_io_set_top_lights(uint32_t lights)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
mapper_write_light(0x20 + i, lights & (1 << i) ? 255 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void popn_io_set_side_lights(uint32_t lights)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
mapper_write_light(0x25 + i, lights & (1 << i) ? 255 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void popn_io_set_button_lights(uint32_t lights)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
// Special case for POPN_LIGHT_SW_LAMP1 which is 4 bits wide
|
||||
mapper_write_light(0x17, lights & 0xf ? 255 : 0);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
mapper_write_light(0x18 + i, lights & (1 << (i + 4)) ? 255 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void popn_io_set_coin_blocker_light(bool enabled)
|
||||
{
|
||||
//mapper_write_light(x, enabled ? 255 : 0);
|
||||
}
|
||||
|
||||
void popn_io_set_coin_counter_light(bool enabled)
|
||||
{
|
||||
//mapper_write_light(x, enabled ? 255 : 0);
|
||||
}
|
||||
12
src/main/popnio/popnio.def
Normal file
12
src/main/popnio/popnio.def
Normal file
@@ -0,0 +1,12 @@
|
||||
LIBRARY popnio
|
||||
|
||||
EXPORTS
|
||||
popn_io_get_buttons
|
||||
popn_io_set_top_lights
|
||||
popn_io_set_side_lights
|
||||
popn_io_set_button_lights
|
||||
popn_io_set_coin_blocker_light
|
||||
popn_io_set_coin_counter_light
|
||||
popn_io_fini
|
||||
popn_io_init
|
||||
popn_io_set_loggers
|
||||
Reference in New Issue
Block a user