1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2024-11-12 01:10:49 +01:00

Support pop'n music 15-18

* popnhook1 for pop'n 15 - 18 has been added
* popnio has been added
* inject.exe has new syntax for loading hook DLLs, `real.dll=hook.dll`. This will trigger an early IAT hook where it will load the EXE suspended without resolving imports, replace the reference to real.dll in the import table with hook.dll, and then resolve everything before launching. This allows for ezusb.dll to be hooked properly.
* launcher.exe also has a new early IAT hook feature now. Use `-I real.dll=hook.dll`. The idea is the same as described above for inject.exe.
* Updated ezusb constant namings based on what is visible in ezusb.dll's debug statements.

The launcher.exe implementation of early IAT hooking means that someone can implement popnhook2.dll for 19 and above. I have tried pop'n music Sunny Park using a modified version of popnhook1 and it seems to work to some degree: the I/O check and security check returns OK which means the ezusb hooking used in popnhook1 is also working for the later games using `launcher.exe -I ezusb.dll=ezusb2-popn-shim.dll ...`. The process is rather invasive (manually resolving all imports means more chances to fail) so it has been implemented in such a way that the launcher will work the same as it has before as long as `-I` isn't specified.

One questionable thing I am not confident about is the `texture_usage_fix` hack flag I added in the conf. As the comment says, pop'n music 16 will work in Windows XP without the flag being set, but the game will immediately crash on later OSes without the flag being set in my experience. No other games had this issue in my experience. Enabling it in other games doesn't seem to have any negative effects.
This commit is contained in:
QCDLZCLW3K 2022-06-10 22:46:59 +00:00 committed by icex2
parent 6e06685551
commit f8a09580ea
66 changed files with 3732 additions and 159 deletions

View File

@ -29,4 +29,4 @@ COPY src src
COPY .git .git
# Building
RUN make
RUN make

View File

@ -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
@ -154,6 +163,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
@ -685,6 +697,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)/
@ -744,6 +776,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 \

View File

@ -70,6 +70,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 +96,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

16
dist/popn/gamestart-15.bat vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -12,6 +12,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

View File

@ -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

View File

@ -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

48
doc/popnhook/README.md Normal file
View 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
View 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.

View 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

View File

@ -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(

View File

@ -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;

View File

@ -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,
};

View File

@ -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
};

View File

@ -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
};

View 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 \

View 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;
}

View 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

View 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 \

View 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;
}

View 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

View 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();
}

View File

@ -0,0 +1,6 @@
#ifndef EZUSB2_POPN_SHIM_PROXY_H
#define EZUSB2_POPN_SHIM_PROXY_H
void ezusb2_proxy_initialize(HMODULE pe);
#endif

View 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

View File

@ -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;
}

View File

@ -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);

View File

@ -8,8 +8,8 @@ libs_inject := \
util \
src_inject := \
main.c \
debugger.c \
logger.c \
main.c \
options.c \
version.c \

View File

@ -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;
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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"

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View 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 \

View 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);
}
}

View 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

View 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");
}

View 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

View 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 \

View 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));
}

View 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

View 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);
}
}

View 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

View 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);
}
}

View 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

View 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);
}

View 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
View 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
View 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

View 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;
}

View 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");
}

View File

@ -0,0 +1,6 @@
#ifndef POPNHOOK1_FILESYSTEM_H
#define POPNHOOK1_FILESYSTEM_H
void filesystem_init(void);
#endif

View File

@ -0,0 +1,4 @@
LIBRARY popnhook1
EXPORTS
DllMain@12 @1 NONAME

10
src/main/popnio/Module.mk Normal file
View 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
View 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);
}

View 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