Quite a lot has happened; I lose track
This commit is contained in:
parent
4464d9188f
commit
f02db82030
15
.gitignore
vendored
15
.gitignore
vendored
@ -1,10 +1,5 @@
|
||||
dist/
|
||||
build/
|
||||
builddir/
|
||||
srcdir/
|
||||
.vscode/
|
||||
|
||||
# Don't distribute the libpcp sources
|
||||
src/micetools/lib/libpcp/*.c
|
||||
# And keep build artifacts out of git!
|
||||
src/libpcp.lib
|
||||
dist/
|
||||
build/
|
||||
builddir/
|
||||
srcdir/
|
||||
.vscode/
|
||||
|
142
Makefile
142
Makefile
@ -1,63 +1,79 @@
|
||||
BUILD_DIR := build
|
||||
BUILD_DIR_32 := $(BUILD_DIR)/build32
|
||||
BUILD_DIR_64 := $(BUILD_DIR)/build64
|
||||
DIST_DIR := dist
|
||||
|
||||
BUILD_DRIVE := M:
|
||||
|
||||
MICE_32 := "$(BUILD_DIR_32)/src\mice.exe"
|
||||
MICE_64 := "$(BUILD_DIR_64)/src\mice.exe"
|
||||
|
||||
VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat"
|
||||
VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat"
|
||||
|
||||
# For windows XP:
|
||||
# VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
|
||||
# VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" -vcvars_ver=14.16
|
||||
|
||||
|
||||
.ONESHELL:
|
||||
|
||||
.PHONY: all
|
||||
all: mice86 dist
|
||||
|
||||
mice86:
|
||||
-@subst $(BUILD_DRIVE) .
|
||||
@cd /D $(BUILD_DRIVE) \
|
||||
& $(VCVARS_32) \
|
||||
& meson setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR_32) \
|
||||
& meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_32)
|
||||
@subst $(BUILD_DRIVE) /D
|
||||
|
||||
mice64:
|
||||
-@subst $(BUILD_DRIVE) .
|
||||
@cd $(BUILD_DRIVE) \
|
||||
& $(VCVARS_64) \
|
||||
& meson setup --cross cross-64.ini $(BUILD_DRIVE)\$(BUILD_DIR_64) \
|
||||
& meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_64)
|
||||
@subst $(BUILD_DRIVE) /D
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@del /S /F /Q $(BUILD_DIR)
|
||||
@rmdir /S /Q $(BUILD_DIR)
|
||||
@del /S /F /Q $(DIST_DIR)
|
||||
@rmdir /S /Q $(DIST_DIR)
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
@-mkdir $(DIST_DIR)
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/micepatch.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
|
||||
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice86.exe"
|
||||
# @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice86.pdb"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice86.pdb"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice86.dll"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice64.exe"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice64.dll"
|
||||
|
||||
@xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*"
|
||||
@xcopy /E /H /C /R /Q /Y src\tools "$(DIST_DIR)\tools/*"
|
||||
@xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*"
|
||||
BUILD_DIR := build
|
||||
BUILD_DIR_32 := $(BUILD_DIR)/build32
|
||||
BUILD_DIR_64 := $(BUILD_DIR)/build64
|
||||
DIST_DIR := dist
|
||||
|
||||
BUILD_DRIVE := M:
|
||||
|
||||
MICE_32 := "$(BUILD_DIR_32)/src\mice.exe"
|
||||
MICE_64 := "$(BUILD_DIR_64)/src\mice.exe"
|
||||
|
||||
VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat"
|
||||
VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat"
|
||||
|
||||
# For windows XP:
|
||||
# VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
|
||||
# VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" -vcvars_ver=14.16
|
||||
|
||||
|
||||
.ONESHELL:
|
||||
|
||||
.PHONY: all
|
||||
all: mice86 dist
|
||||
|
||||
mice86:
|
||||
-@subst $(BUILD_DRIVE) .
|
||||
@cd /D $(BUILD_DRIVE) \
|
||||
& $(VCVARS_32) \
|
||||
& meson setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR_32) \
|
||||
& meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_32)
|
||||
@subst $(BUILD_DRIVE) /D
|
||||
|
||||
mice64:
|
||||
-@subst $(BUILD_DRIVE) .
|
||||
@cd $(BUILD_DRIVE) \
|
||||
& $(VCVARS_64) \
|
||||
& meson setup --cross cross-64.ini $(BUILD_DRIVE)\$(BUILD_DIR_64) \
|
||||
& meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_64)
|
||||
@subst $(BUILD_DRIVE) /D
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@del /S /F /Q $(BUILD_DIR)
|
||||
@rmdir /S /Q $(BUILD_DIR)
|
||||
@del /S /F /Q $(DIST_DIR)
|
||||
@rmdir /S /Q $(DIST_DIR)
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
@-mkdir $(DIST_DIR) > NUL 2>&1
|
||||
@-mkdir $(DIST_DIR)\util > NUL 2>&1
|
||||
@-mkdir $(DIST_DIR)\Execute > NUL 2>&1
|
||||
@-mkdir $(DIST_DIR)\Execute\Z > NUL 2>&1
|
||||
@-mkdir $(DIST_DIR)\Execute\S > NUL 2>&1
|
||||
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
|
||||
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice86.exe"
|
||||
# @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice86.pdb"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice86.pdb"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice86.dll"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice64.exe"
|
||||
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice64.dll"
|
||||
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\miceprestartup.exe" "$(DIST_DIR)/Execute/miceprestartup.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\micestartup.exe" "$(DIST_DIR)/Execute/micestartup.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\TrueCrypt.exe" "$(DIST_DIR)/Execute/TrueCrypt.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe"
|
||||
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/util/micepatch.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micedump.exe" "$(DIST_DIR)/util/micedump.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micetinker.exe" "$(DIST_DIR)/util/micetinker.exe"
|
||||
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micemonitor.exe" "$(DIST_DIR)/util/micemonitor.exe"
|
||||
|
||||
@copy /Y "src/micetools/miceboot\TrueCrypt.cmd" "$(DIST_DIR)/Execute/TrueCrypt.cmd"
|
||||
|
||||
@xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*"
|
||||
@xcopy /E /H /C /R /Q /Y src\tools "$(DIST_DIR)\tools/*"
|
||||
@xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*"
|
||||
|
62
assert_dd_blocks.py
Normal file
62
assert_dd_blocks.py
Normal file
@ -0,0 +1,62 @@
|
||||
MBR_LBA_GAP = 0x3f
|
||||
BOOT_PARITION_SIZE = 0x300B85
|
||||
RECOVER_PARTITION_SIZE = 0x300BC4
|
||||
partitions = [
|
||||
0x102d83,
|
||||
0x403947,
|
||||
0x403947,
|
||||
0x48ed459,
|
||||
0x20014aa,
|
||||
]
|
||||
|
||||
|
||||
ext_offset = 0
|
||||
offsets = [0] * len(partitions)
|
||||
extended_base = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE
|
||||
for i in range(len(partitions)):
|
||||
offsets[i] = ext_offset + extended_base
|
||||
ext_offset += partitions[i] + MBR_LBA_GAP
|
||||
|
||||
# (Start, end, data)
|
||||
accounted_for = [
|
||||
(0, 1, True), # MBR
|
||||
(1, MBR_LBA_GAP, False),
|
||||
(MBR_LBA_GAP, MBR_LBA_GAP + BOOT_PARITION_SIZE, True),
|
||||
(MBR_LBA_GAP + BOOT_PARITION_SIZE, MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE, True),
|
||||
]
|
||||
|
||||
for n, (i, j) in enumerate(zip(offsets, partitions)):
|
||||
accounted_for.append((
|
||||
i, i + 1, True
|
||||
))
|
||||
if n == 0:
|
||||
# SBR
|
||||
accounted_for.append((
|
||||
i + 1, i + 4, True
|
||||
))
|
||||
accounted_for.append((
|
||||
i + 4, i + MBR_LBA_GAP, False
|
||||
))
|
||||
else:
|
||||
accounted_for.append((
|
||||
i + 1, i + MBR_LBA_GAP, False
|
||||
))
|
||||
accounted_for.append((
|
||||
i + MBR_LBA_GAP, i + MBR_LBA_GAP + j, True
|
||||
))
|
||||
|
||||
assert accounted_for[-1][1] == 0x77fa1d7
|
||||
last = 0
|
||||
for i in accounted_for:
|
||||
assert i[0] == last
|
||||
last = i[1]
|
||||
|
||||
with open(r"G:\finale_dd\finale_dd.img", "rb") as finale_dd:
|
||||
for i in accounted_for:
|
||||
if i[2]:
|
||||
continue
|
||||
nbytes = i[1] - i[0]
|
||||
finale_dd.seek(i[0] * 512)
|
||||
print(f"Checking at {i[0] * 512:012x}-{i[1] * 512:012x}")
|
||||
if any(finale_dd.read(nbytes * 512)):
|
||||
print("!! FAIL")
|
76
meson.build
76
meson.build
@ -1,30 +1,46 @@
|
||||
project('micetools', 'c', default_options: [
|
||||
'buildtype=minsize',
|
||||
# ! Tobble /\ and \/ when building for XP (minsize=normal, static=XP)
|
||||
# 'b_vscrt=static_from_buildtype',
|
||||
'warning_level=2',
|
||||
])
|
||||
|
||||
winxp = false
|
||||
subsystem = 'console,5.01'
|
||||
|
||||
if (host_machine.cpu_family() == 'x86')
|
||||
add_project_arguments('-DMICE_WIN32', language: 'c')
|
||||
endif
|
||||
|
||||
add_project_arguments(
|
||||
'/DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need
|
||||
'/D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it
|
||||
language: 'c',
|
||||
)
|
||||
if winxp
|
||||
add_project_arguments(
|
||||
'/D_USING_V140_SDK71_',
|
||||
'/DSFML_STATIC',
|
||||
'/DYNAMICBASE:NO',
|
||||
language: 'c',
|
||||
)
|
||||
endif
|
||||
|
||||
subdir('assets')
|
||||
subdir('src')
|
||||
project('micetools', 'c', default_options: [
|
||||
'buildtype=minsize',
|
||||
# ! Toggle /\ and \/ when building for XP (minsize=normal, static=XP)
|
||||
# 'b_vscrt=static_from_buildtype',
|
||||
'warning_level=3',
|
||||
])
|
||||
|
||||
winxp = false
|
||||
subsystem = 'console,5.01'
|
||||
|
||||
if (host_machine.cpu_family() == 'x86')
|
||||
add_project_arguments('-DMICE_WIN32', language: 'c')
|
||||
endif
|
||||
|
||||
add_project_arguments(
|
||||
'/DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need
|
||||
'/D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it
|
||||
|
||||
'/wd4706', # assignment within conditional expression
|
||||
'/wd4214', # windns.h: nonstandard extension used: bit field types other than int
|
||||
'/wd4201', # ewfapi.h: nameless struct/union
|
||||
'/wd4200', # zero-sized arrays
|
||||
'/wd4152', # hooks: function/data pointer conversion in expression
|
||||
'/wd4100', # basically every hook causes "unreferenced formal parameter"
|
||||
'/wd4206', # empty C files
|
||||
|
||||
'/wd4189', # lots of keychip functions aren't 100% implemented yet
|
||||
|
||||
'/we4047', # ... differs in levels of indirection from ...
|
||||
'/we4057', # ... differs in levels of indirection (slightly) from ...
|
||||
'/we4024', # ... different types for formal and actual paramter ...
|
||||
'/we4013', # ... undefined; assuming extern returning int
|
||||
|
||||
language: 'c',
|
||||
)
|
||||
if winxp
|
||||
add_project_arguments(
|
||||
'/D_USING_V140_SDK71_',
|
||||
'/DSFML_STATIC',
|
||||
'/DYNAMICBASE:NO',
|
||||
language: 'c',
|
||||
)
|
||||
endif
|
||||
|
||||
subdir('assets')
|
||||
subdir('src')
|
||||
|
159
mxinstaller.py
Normal file
159
mxinstaller.py
Normal file
@ -0,0 +1,159 @@
|
||||
from pprint import pformat, pprint
|
||||
import socket
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(("127.0.0.1", 12121))
|
||||
|
||||
|
||||
slots = [
|
||||
"original0",
|
||||
"original1",
|
||||
"patch0",
|
||||
"patch1",
|
||||
"os",
|
||||
"app_data",
|
||||
"originalf",
|
||||
"originalb",
|
||||
"patchf",
|
||||
"patchb",
|
||||
]
|
||||
|
||||
|
||||
"""
|
||||
slot 0: OS
|
||||
os result=success&status=complete&id=AAS0&version=4524545&time=00000000000000&segcount=1745&segsize=262144&hw=AAS&instant=0&osver=4524545&ossegcount=0&orgtime=00000000000000&orgversion=4524545
|
||||
|
||||
slot 1: original0
|
||||
original0 result=success&status=complete&id=SDEY&version=65633&time=20181029150736&segcount=65082&segsize=262144&hw=AAS&instant=0&osver=4524545&ossegcount=1745&orgtime=20181029150736&orgversion=65633
|
||||
|
||||
slot 2: ??
|
||||
|
||||
slot 3: ??
|
||||
|
||||
slot 4: ??
|
||||
|
||||
|
||||
original1 result=error&status=error&code=40
|
||||
patch0 result=success&status=empty
|
||||
patch1 result=success&status=complete&id=SDEY&version=65634&time=20181116190448&segcount=173&segsize=262144&hw=AAS&instant=0&osver=0&ossegcount=0&orgtime=20181029150736&orgversion=65633
|
||||
app_data result=invalid_parameter
|
||||
originalf result=success&status=complete&id=SDEY&version=65633&time=20181029150736&segcount=65082&segsize=262144&hw=AAS&instant=0&osver=4524545&ossegcount=1745&orgtime=20181029150736&orgversion=65633
|
||||
originalb result=error&status=error&code=40
|
||||
patchf result=success&status=complete&id=SDEY&version=65634&time=20181116190448&segcount=173&segsize=262144&hw=AAS&instant=0&osver=0&ossegcount=0&orgtime=20181029150736&orgversion=65633
|
||||
patchb result=success&status=empty
|
||||
"""
|
||||
def recv_pcp():
|
||||
resp = s.recv(4096).decode().strip()
|
||||
if resp == "?":
|
||||
raise Exception("PCP Failed")
|
||||
parts = resp.split("&")
|
||||
return {i.split("=")[0]: i.split("=")[1] for i in parts}
|
||||
def send_pcp(request, **kwargs):
|
||||
req = f"request={request}"
|
||||
if kwargs:
|
||||
req += "&" + "&".join(f"{i}={kwargs[i]}" for i in kwargs)
|
||||
assert s.recv(4096) == b">"
|
||||
s.send(req.encode() + b"\r\n")
|
||||
def pcp(request, **kwargs):
|
||||
send_pcp(request, **kwargs)
|
||||
ret = recv_pcp()
|
||||
if ret["result"] != "success" or ret["response"] != request:
|
||||
raise Exception(f"PCP Failed:\n{pformat(ret)}")
|
||||
del ret["response"]
|
||||
del ret["result"]
|
||||
return ret
|
||||
|
||||
print("Query slots:")
|
||||
for slot in slots:
|
||||
assert s.recv(4096) == b">"
|
||||
s.send(f"request=query_slot_status&slot={slot}\r\n".encode())
|
||||
print(slot.ljust(20), s.recv(4096).decode().strip())
|
||||
|
||||
# assert s.recv(4096) == b">"
|
||||
# s.send(f"request=check&slot={slot}\r\n".encode())
|
||||
# print(slot.ljust(20), s.recv(4096).decode().strip())
|
||||
|
||||
print("-" * 10)
|
||||
|
||||
if pcp("query_semaphore_status")["semaphore"] != "1":
|
||||
print("Unable to get semaphore!")
|
||||
quit()
|
||||
|
||||
gsem = pcp("get_semaphore")
|
||||
semid = gsem["semid"]
|
||||
try:
|
||||
spd = pcp("query_spd")
|
||||
br = pcp("query_br")
|
||||
bootslot = pcp("query_sbr_bootslot")
|
||||
print("=== SPD ===")
|
||||
order = spd.pop("order")
|
||||
print(f"--- Order: {order}")
|
||||
spd = list(spd.items())
|
||||
spd.sort(key=lambda x: int(x[1]))
|
||||
for i in spd:
|
||||
# Values here are uk3 * block_size
|
||||
print(f" - {(i[0] + ':').ljust(10)} {int(i[1]):016x}")
|
||||
print(f"--- Bootslot: {bootslot['bootslot']}")
|
||||
print("=== BR ===")
|
||||
pprint(br)
|
||||
quit()
|
||||
|
||||
assert s.recv(4096) == b">"
|
||||
s.send((
|
||||
b"request=check&"
|
||||
b"slot=original0&"
|
||||
b"segoffset=0&"
|
||||
b"segcount=100000&"
|
||||
b"force=1&"
|
||||
b"semid=" + sem + b""
|
||||
b"\r\n"
|
||||
))
|
||||
print(s.recv(4096).decode().strip())
|
||||
|
||||
assert s.recv(4096) == b">"
|
||||
s.send((
|
||||
b"request=release_semaphore&"
|
||||
b"semid=" + sem + b""
|
||||
b"\r\n"
|
||||
))
|
||||
print(s.recv(4096).decode().strip())
|
||||
|
||||
quit()
|
||||
|
||||
# assert s.recv(4096) == b">"
|
||||
# s.send(b"request=set_sbr_bootslot&bootslot=cd\r\n")
|
||||
# print(s.recv(4096).decode().strip())
|
||||
assert s.recv(4096) == b">"
|
||||
s.send(b"request=query_application_status\r\n")
|
||||
print(s.recv(4096).decode().strip())
|
||||
assert s.recv(4096) == b">"
|
||||
s.send(b"request=query_br\r\n")
|
||||
print(s.recv(4096).decode().strip())
|
||||
assert s.recv(4096) == b">"
|
||||
s.send((
|
||||
b"request=appdata&"
|
||||
b"slot=os&"
|
||||
b"semid=" + sem + b"&"
|
||||
b"\r\n"
|
||||
))
|
||||
# s.send((
|
||||
# b"request=install&"
|
||||
# b"slot=patch0&"
|
||||
# b"segoffset=3&"
|
||||
# b"id=SDEY&"
|
||||
# b"version=010061&"
|
||||
# b"time=20181029150736&"
|
||||
# b"segcount=fe3a&"
|
||||
# b"segsize=040000&"
|
||||
# b"hw=AAS&"
|
||||
# b"instant=3&"
|
||||
# b"osver=450a01&"
|
||||
# b"ossegcount=06d1&"
|
||||
# b"orgtime=20181029150736&"
|
||||
# b"orgversion=10061&"
|
||||
# b"semid=" + sem + b"&"
|
||||
# b"\r\n"
|
||||
# ))
|
||||
print(s.recv(4096).decode().strip())
|
||||
finally:
|
||||
pcp("release_semaphore", semid=semid)
|
@ -1,116 +1,191 @@
|
||||
#include "comdevice.h"
|
||||
|
||||
BOOL DevGetCommState(void* data, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL DevSetCommState(void* data, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
|
||||
BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
|
||||
BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
|
||||
BOOL DevPurgeComm(void* data, DWORD dwFlags) {
|
||||
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) {
|
||||
// TODO: JVS SENSE
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
WaitForSingleObject(((com_device_t*)data)->event, INFINITE);
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) {
|
||||
if (lpErrors != NULL) *lpErrors = 0;
|
||||
if (lpStat != NULL) {
|
||||
lpStat->fCtsHold = FALSE;
|
||||
lpStat->fDsrHold = FALSE;
|
||||
lpStat->fRlsdHold = FALSE;
|
||||
lpStat->fXoffHold = FALSE;
|
||||
lpStat->fXoffSent = FALSE;
|
||||
lpStat->fEof = FALSE;
|
||||
lpStat->fTxim = FALSE;
|
||||
lpStat->fReserved = 0;
|
||||
lpStat->cbInQue = ringbuf_available(&((com_device_t*)data)->out);
|
||||
lpStat->cbOutQue = ringbuf_available(&((com_device_t*)data)->in);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DevWriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
if (nNumberOfBytesToWrite > 0xffff) return FALSE;
|
||||
// Ignore overflow
|
||||
ringbuf_write(&((com_device_t*)file)->in, lpBuffer, nNumberOfBytesToWrite & 0xffff);
|
||||
if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
if (nNumberOfBytesToRead > 0xffff) return FALSE;
|
||||
|
||||
// Make sure we have at least one byte to return
|
||||
// while (!ringbuf_available(&((com_device_t*)file)->out)) {
|
||||
// WaitForSingleObject(((com_device_t*)file)->event, INFINITE);
|
||||
// }
|
||||
|
||||
short read = ringbuf_read(&((com_device_t*)file)->out, lpBuffer, nNumberOfBytesToRead & 0xffff);
|
||||
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read;
|
||||
|
||||
if (read != 0) {
|
||||
// log_info("drf", "%d", read);
|
||||
// for (int i = 0; i < read; i++) {
|
||||
// printf("%02x ", ((unsigned char*)lpBuffer)[i]);
|
||||
// }
|
||||
// puts("");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes) {
|
||||
return ringbuf_read(&com->in, buffer, bytes);
|
||||
}
|
||||
bool comdev_write(com_device_t* com, unsigned char* buffer, short bytes) {
|
||||
bool ret = ringbuf_write(&com->out, buffer, bytes);
|
||||
SetEvent(com->event);
|
||||
return ret;
|
||||
}
|
||||
short comdev_available(com_device_t* com) { return ringbuf_available(&com->in); }
|
||||
|
||||
void com_device_thread(com_device_t* com, FnComDeviceThread* thread) {
|
||||
com->thread = CreateThread(NULL, 0, thread, com, 0, NULL);
|
||||
}
|
||||
|
||||
com_device_t* new_com_device(BYTE port) {
|
||||
com_device_t* hook = (com_device_t*)malloc(sizeof *hook);
|
||||
com_hook_t* com = new_com_hook(port);
|
||||
file_hook_t* file = new_file_hook(com->wName);
|
||||
file->altFilename = com->wDosName;
|
||||
com->data = hook;
|
||||
file->data = hook;
|
||||
hook->com = com;
|
||||
hook->file = file;
|
||||
|
||||
com->GetCommState = DevGetCommState;
|
||||
com->SetCommState = DevSetCommState;
|
||||
com->GetCommTimeouts = DevGetCommTimeouts;
|
||||
com->SetCommTimeouts = DevSetCommTimeouts;
|
||||
com->SetupComm = DevSetupComm;
|
||||
com->PurgeComm = DevPurgeComm;
|
||||
com->GetCommModemStatus = DevGetCommModemStatus;
|
||||
com->WaitCommEvent = DevWaitCommEvent;
|
||||
com->ClearCommError = DevClearCommError;
|
||||
|
||||
file->ReadFile = DevReadFile;
|
||||
file->WriteFile = DevWriteFile;
|
||||
|
||||
ringbuf_purge(&hook->in);
|
||||
ringbuf_purge(&hook->out);
|
||||
hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName);
|
||||
|
||||
hook_file(file);
|
||||
hook_com(com);
|
||||
free(com->virtual_handle);
|
||||
com->virtual_handle = file->virtual_handle;
|
||||
|
||||
return hook;
|
||||
}
|
||||
#include "comdevice.h"
|
||||
|
||||
BOOL DevGetCommState(void* data, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL DevSetCommState(void* data, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
|
||||
BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
|
||||
BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
|
||||
BOOL DevPurgeComm(void* data, DWORD dwFlags) {
|
||||
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) {
|
||||
// TODO: JVS SENSE
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
WaitForSingleObject(((com_device_t*)data)->event, INFINITE);
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) {
|
||||
if (lpErrors != NULL) *lpErrors = 0;
|
||||
if (lpStat != NULL) {
|
||||
lpStat->fCtsHold = FALSE;
|
||||
lpStat->fDsrHold = FALSE;
|
||||
lpStat->fRlsdHold = FALSE;
|
||||
lpStat->fXoffHold = FALSE;
|
||||
lpStat->fXoffSent = FALSE;
|
||||
lpStat->fEof = FALSE;
|
||||
lpStat->fTxim = FALSE;
|
||||
lpStat->fReserved = 0;
|
||||
lpStat->cbInQue = ringbuf_available(&((com_device_t*)data)->out);
|
||||
lpStat->cbOutQue = ringbuf_available(&((com_device_t*)data)->in);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DevWriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
|
||||
if (nNumberOfBytesToWrite > 0xffff) return FALSE;
|
||||
// Ignore overflow
|
||||
ringbuf_write(&((com_device_t*)file)->in, lpBuffer, nNumberOfBytesToWrite & 0xffff);
|
||||
if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
|
||||
if (nNumberOfBytesToRead > 0xffff) return FALSE;
|
||||
|
||||
// Make sure we have at least one byte to return
|
||||
// while (!ringbuf_available(&((com_device_t*)file)->out)) {
|
||||
// WaitForSingleObject(((com_device_t*)file)->event, INFINITE);
|
||||
// }
|
||||
|
||||
short read = ringbuf_read(&((com_device_t*)file)->out, lpBuffer, nNumberOfBytesToRead & 0xffff);
|
||||
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read;
|
||||
|
||||
if (read != 0) {
|
||||
// log_info("drf", "%d", read);
|
||||
// for (int i = 0; i < read; i++) {
|
||||
// printf("%02x ", ((LPBYTE)lpBuffer)[i]);
|
||||
// }
|
||||
// puts("");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes) {
|
||||
while (comdev_available(com) < bytes) SwitchToThread();
|
||||
return ringbuf_read(&com->in, buffer, bytes);
|
||||
}
|
||||
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes) {
|
||||
return ringbuf_read(&com->in, buffer, bytes);
|
||||
}
|
||||
bool comdev_write(com_device_t* com, const unsigned char* buffer, short bytes) {
|
||||
bool ret = ringbuf_write(&com->out, buffer, bytes);
|
||||
SetEvent(com->event);
|
||||
return ret;
|
||||
}
|
||||
short comdev_available(com_device_t* com) { return ringbuf_available(&com->in); }
|
||||
BYTE comdev_peek(com_device_t* com) { return com->in.buffer[com->in.read]; }
|
||||
|
||||
BYTE one_byte;
|
||||
// Read data from a com device, unescaping as we go
|
||||
void comio_read(com_device_t* com, BYTE* data, BYTE len) {
|
||||
for (; len; len--) {
|
||||
comdev_read_blocking(com, &one_byte, 1);
|
||||
if (one_byte == COMIO_MARK) {
|
||||
comdev_read_blocking(com, &one_byte, 1);
|
||||
one_byte++;
|
||||
}
|
||||
*(data++) = one_byte;
|
||||
}
|
||||
}
|
||||
// Write data to a com device, escaping as we go
|
||||
void comio_write(com_device_t* com, BYTE* data, BYTE len) {
|
||||
for (; len; len--) {
|
||||
one_byte = *(data++);
|
||||
if (one_byte == COMIO_MARK || one_byte == COMIO_SYNC) {
|
||||
BYTE mark = COMIO_MARK;
|
||||
comdev_write(com, &mark, 1);
|
||||
one_byte--;
|
||||
}
|
||||
comdev_write(com, &one_byte, 1);
|
||||
}
|
||||
}
|
||||
void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data) {
|
||||
do {
|
||||
if (comdev_available(com) < (sizeof *head + 1)) {
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
comdev_read(com, &one_byte, 1);
|
||||
if (one_byte != COMIO_SYNC) {
|
||||
log_error("com", "Garbage on JVS: %02x", one_byte);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
comio_read(com, (LPBYTE)head, sizeof *head);
|
||||
|
||||
// TODO: Validate the sum? Do we care really?
|
||||
comio_read(com, data, head->length);
|
||||
unsigned char sum;
|
||||
comio_read(com, &sum, 1);
|
||||
}
|
||||
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len,
|
||||
BYTE* data) {
|
||||
one_byte = COMIO_SYNC;
|
||||
comdev_write(com, &one_byte, 1);
|
||||
|
||||
comio_resp_head_t resp = {
|
||||
.frame_length = len + sizeof resp,
|
||||
.src = req->dst,
|
||||
.seq = req->seq,
|
||||
.status = status,
|
||||
.op = req->op,
|
||||
.length = len,
|
||||
};
|
||||
// Header
|
||||
comio_write(com, (LPBYTE)&resp, sizeof resp);
|
||||
// Payload
|
||||
if (len) // If len == 0, we allow data to be null
|
||||
comio_write(com, data, len);
|
||||
// Checksum
|
||||
one_byte = 0;
|
||||
for (BYTE i = 0; i < sizeof resp; i++)
|
||||
one_byte += ((LPBYTE)&resp)[i];
|
||||
for (BYTE i = 0; i < len; i++)
|
||||
one_byte += data[i];
|
||||
comio_write(com, &one_byte, 1);
|
||||
}
|
||||
|
||||
void com_device_thread(com_device_t* com, FnComDeviceThread* thread) {
|
||||
com->thread = CreateThread(NULL, 0, thread, com, 0, NULL);
|
||||
}
|
||||
|
||||
com_device_t* new_com_device(BYTE port) {
|
||||
com_device_t* hook = (com_device_t*)malloc(sizeof *hook);
|
||||
com_hook_t* com = new_com_hook(port);
|
||||
file_hook_t* file = new_file_hook(com->wName);
|
||||
file->altFilename = com->wDosName;
|
||||
com->data = hook;
|
||||
file->data = hook;
|
||||
hook->com = com;
|
||||
hook->file = file;
|
||||
|
||||
com->GetCommState = DevGetCommState;
|
||||
com->SetCommState = DevSetCommState;
|
||||
com->GetCommTimeouts = DevGetCommTimeouts;
|
||||
com->SetCommTimeouts = DevSetCommTimeouts;
|
||||
com->SetupComm = DevSetupComm;
|
||||
com->PurgeComm = DevPurgeComm;
|
||||
com->GetCommModemStatus = DevGetCommModemStatus;
|
||||
com->WaitCommEvent = DevWaitCommEvent;
|
||||
com->ClearCommError = DevClearCommError;
|
||||
|
||||
file->ReadFile = DevReadFile;
|
||||
file->WriteFile = DevWriteFile;
|
||||
|
||||
ringbuf_purge(&hook->in);
|
||||
ringbuf_purge(&hook->out);
|
||||
hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName);
|
||||
|
||||
hook_file(file);
|
||||
hook_com(com);
|
||||
|
||||
return hook;
|
||||
}
|
||||
|
@ -1,23 +1,54 @@
|
||||
#pragma once
|
||||
#include "hooks/com.h"
|
||||
#include "common.h"
|
||||
#include "hooks/files.h"
|
||||
|
||||
typedef struct com_device {
|
||||
com_hook_t* com;
|
||||
file_hook_t* file;
|
||||
|
||||
ring_buffer_t in;
|
||||
ring_buffer_t out;
|
||||
HANDLE event;
|
||||
HANDLE thread;
|
||||
} com_device_t;
|
||||
|
||||
typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com);
|
||||
|
||||
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes);
|
||||
bool comdev_write(com_device_t* com, unsigned char* buffer, short bytes);
|
||||
short comdev_available(com_device_t* com);
|
||||
|
||||
void com_device_thread(com_device_t* com, FnComDeviceThread* thread);
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include "hooks/com.h"
|
||||
#include "hooks/files.h"
|
||||
|
||||
typedef struct com_device {
|
||||
com_hook_t* com;
|
||||
file_hook_t* file;
|
||||
|
||||
ring_buffer_t in;
|
||||
ring_buffer_t out;
|
||||
HANDLE event;
|
||||
HANDLE thread;
|
||||
} com_device_t;
|
||||
|
||||
typedef struct {
|
||||
BYTE frame_length;
|
||||
BYTE dst;
|
||||
BYTE seq;
|
||||
BYTE op;
|
||||
BYTE length;
|
||||
} comio_recv_head_t;
|
||||
|
||||
typedef struct {
|
||||
BYTE frame_length;
|
||||
BYTE src;
|
||||
BYTE seq;
|
||||
BYTE op;
|
||||
BYTE status;
|
||||
BYTE length;
|
||||
} comio_resp_head_t;
|
||||
|
||||
#define COMIO_SYNC 0xE0
|
||||
#define COMIO_MARK 0xD0
|
||||
|
||||
#define COMIO_STATUS_OK 0
|
||||
#define COMIO_STATUS_NG 1
|
||||
|
||||
typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com);
|
||||
|
||||
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes);
|
||||
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes);
|
||||
bool comdev_write(com_device_t* com, const unsigned char* buffer, short bytes);
|
||||
short comdev_available(com_device_t* com);
|
||||
BYTE comdev_peek(com_device_t* com);
|
||||
|
||||
void comio_read(com_device_t* com, BYTE* data, BYTE len);
|
||||
void comio_write(com_device_t* com, BYTE* data, BYTE len);
|
||||
|
||||
void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data);
|
||||
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, BYTE* data);
|
||||
|
||||
void com_device_thread(com_device_t* com, FnComDeviceThread* thread);
|
||||
com_device_t* new_com_device(BYTE port);
|
@ -1,24 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Winsock2.h>
|
||||
#include <initguid.h>
|
||||
#include <windns.h>
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#include <shlwapi.h>
|
||||
#pragma comment(lib, "d3d9.lib")
|
||||
#include <d3d9.h>
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
#include <Iphlpapi.h>
|
||||
#include <commctrl.h>
|
||||
#include <memory.h>
|
||||
#include <setupapi.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "./util/_util.h"
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Winsock2.h>
|
||||
#include <initguid.h>
|
||||
#include <windns.h>
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#include <shlwapi.h>
|
||||
#pragma comment(lib, "d3d9.lib")
|
||||
#include <d3d9.h>
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
#include <Iphlpapi.h>
|
||||
#include <commctrl.h>
|
||||
#include <memory.h>
|
||||
#include <setupapi.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "./util/_util.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "_devices.h"
|
||||
|
||||
void install_devices() {
|
||||
install_led_bd();
|
||||
install_touch_bd();
|
||||
}
|
||||
#include "_devices.h"
|
||||
|
||||
void install_devices() {
|
||||
install_led_bd();
|
||||
install_touch_bd();
|
||||
install_aime_bd();
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include "../comdevice.h"
|
||||
#include "../common.h"
|
||||
|
||||
void install_led_bd();
|
||||
void install_touch_bd();
|
||||
|
||||
#pragma once
|
||||
#include "../comdevice.h"
|
||||
#include "../common.h"
|
||||
|
||||
void install_led_bd();
|
||||
void install_touch_bd();
|
||||
void install_aime_bd();
|
||||
|
||||
void install_devices();
|
90
src/micetools/dll/devices/aime_bd.c
Normal file
90
src/micetools/dll/devices/aime_bd.c
Normal file
@ -0,0 +1,90 @@
|
||||
#include "_devices.h"
|
||||
|
||||
static BYTE read_one(com_device_t* dev) {
|
||||
while (!comdev_available(dev)) Sleep(50);
|
||||
BYTE data;
|
||||
comdev_read(dev, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
BYTE extra[0xff];
|
||||
|
||||
#define GetFWVersion 0x30
|
||||
#define GetHWVersion 0x32
|
||||
#define RadioOn 0x40
|
||||
#define RadioOff 0x41
|
||||
#define Poll 0x2
|
||||
#define MifareSelectTag 0x43
|
||||
#define Unknown1 0x44 // Present in code, not seen used
|
||||
#define SetKeyBana 0x50
|
||||
#define Unknown2 0x51 // Present in code, not seen used
|
||||
#define ReadBlock 0x52
|
||||
#define SetKeyAime 0x54
|
||||
#define Authenticate 0x55
|
||||
#define Unknown3 0x60 // Present in code, not seen used
|
||||
#define Unknown4 0x61 // Present in code, not seen used
|
||||
#define Reset 0x62
|
||||
#define Unknown5 0x70 // Present in code, not seen used
|
||||
#define FelicaEncap 0x71
|
||||
|
||||
#define LedReset 0xf5
|
||||
#define LedGetInfo 0xf0
|
||||
#define LedSetColour 0x81
|
||||
|
||||
#define FWVer "TN32MSEC003S F/W Ver1.2"
|
||||
#define HWVer "TN32MSEC003S H/W Ver3.0"
|
||||
|
||||
DWORD WINAPI aime_bd_thread(com_device_t* dev) {
|
||||
log_warning("aime_bd", "%ls woke up", dev->com->wName);
|
||||
while (1) {
|
||||
comio_recv_head_t req;
|
||||
comio_next_req(dev, &req, extra);
|
||||
|
||||
log_info("aime_bd", "(%d) %02x", req.dst, req.op);
|
||||
|
||||
if (req.dst == 0x00 || req.dst == 0x01) {
|
||||
// Aime readers
|
||||
switch (req.op) {
|
||||
case Reset:
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
|
||||
break;
|
||||
case GetFWVersion:
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, (LPBYTE)FWVer);
|
||||
break;
|
||||
case GetHWVersion:
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, (LPBYTE)HWVer);
|
||||
break;
|
||||
case SetKeyAime:
|
||||
log_info("aime_bd", "Aime key: %.*s", req.length, extra);
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
|
||||
break;
|
||||
case SetKeyBana:
|
||||
log_info("aime_bd", "Bana key: %.*s", req.length, extra);
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
|
||||
break;
|
||||
}
|
||||
} else if (req.dst == 0x08 || req.dst == 0x09) {
|
||||
// LED sub-boards
|
||||
switch (req.op) {
|
||||
case LedReset:
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
|
||||
break;
|
||||
case LedGetInfo:
|
||||
// TODO: I'm not sure what this actually means.
|
||||
// 838-15084 is probably a part number
|
||||
comio_reply(dev, &req, COMIO_STATUS_OK, 9, (BYTE*)"15084\xff\x10\x00\x12");
|
||||
break;
|
||||
case LedSetColour:
|
||||
// No response expected here!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
void install_aime_bd() {
|
||||
com_device_t* aime = new_com_device(2);
|
||||
com_device_thread(aime, aime_bd_thread);
|
||||
}
|
@ -1,225 +1,222 @@
|
||||
#include "../hooks/gui.h"
|
||||
#include "_devices.h"
|
||||
|
||||
/*
|
||||
[0] = e0
|
||||
[1] = dest?
|
||||
[2] = dst?
|
||||
[3] = length
|
||||
[4] = op code
|
||||
[...] length-1 bytes
|
||||
[.] = sum
|
||||
|
||||
[0] = e0
|
||||
[2] = dst?
|
||||
[1] = dest?
|
||||
[3] = length
|
||||
[4] = status
|
||||
[5] = op
|
||||
[6] = report
|
||||
[...]
|
||||
[.] = sum
|
||||
|
||||
OP codes:
|
||||
3c: FUN_005735c0 (1)
|
||||
|
||||
10: FUN_00580c00 (1)
|
||||
7c: FUN_00580c00 (2)
|
||||
3c: FUN_00580c00 (1)
|
||||
39: FUN_00580c00 (4)
|
||||
3b: FUN_00580c00 (1)
|
||||
|
||||
31: FUN_00581350 (5)
|
||||
32: FUN_005813b0 (8)
|
||||
33: FUN_00581430 (8) -> something at [16]??
|
||||
39: FUN_005814b0 (4)
|
||||
3f: FUN_00581220 (7)
|
||||
|
||||
7b: FUN_005812a0 (3)
|
||||
7c: FUN_00581310 (2)
|
||||
|
||||
01: was this just an error?
|
||||
10:
|
||||
|
||||
31: Set button. [button] [r] [g] [b]
|
||||
0-7 = buttons
|
||||
8 = woofer
|
||||
9 = center
|
||||
32: Set multiple. [00] [idx hi] [idx lo] [r] [g] [b]
|
||||
33: Fade multiple?. [09] [?] [?] [r] [g] [b]
|
||||
39: Set body light. [intensity] [-] [-]
|
||||
3b:
|
||||
3c: Commit?
|
||||
3f:
|
||||
|
||||
7c:
|
||||
7b:
|
||||
|
||||
initial setup: 7c 0-7, 32, 3c, 39, 3f, 3b
|
||||
*/
|
||||
|
||||
unsigned char COLOURS[10][3];
|
||||
double positions[10][2] = {
|
||||
{ 0.337963, 0.470833 }, { 0.469444, 0.619792 }, { 0.469444, 0.828125 }, { 0.337037, 0.977083 },
|
||||
{ 0.152778, 0.976042 }, { 0.020370, 0.828125 }, { 0.020370, 0.618750 }, { 0.151852, 0.472917 },
|
||||
{ 0.5, 0.75 }, { 0.5, 0.5 },
|
||||
};
|
||||
|
||||
typedef struct rs232c_recv_head {
|
||||
BYTE sync;
|
||||
BYTE src;
|
||||
BYTE dst;
|
||||
BYTE length;
|
||||
BYTE op;
|
||||
} rs232c_recv_head_t;
|
||||
|
||||
static DWORD WINAPI led_bd_thread(com_device_t* dev) {
|
||||
log_warning("led_bd", "%ls woke up", dev->com->wName);
|
||||
while (1) {
|
||||
rs232c_recv_head_t head;
|
||||
if (comdev_available(dev) < sizeof head) {
|
||||
// Sleep(100);
|
||||
continue;
|
||||
}
|
||||
comdev_read(dev, (char*)&head, sizeof head);
|
||||
|
||||
unsigned char* extra = malloc(head.length);
|
||||
comdev_read(dev, extra, head.length);
|
||||
|
||||
// log_info("led_bd", "Bound %02x->%02x", head.src, head.dst);
|
||||
|
||||
switch (head.op) {
|
||||
case 0x01:
|
||||
log_warning("led_bd", "01");
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x01\x01\x18", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
log_warning("led_bd", "10");
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x10\x01\x27", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
COLOURS[extra[0]][0] = extra[1];
|
||||
COLOURS[extra[0]][1] = extra[2];
|
||||
COLOURS[extra[0]][2] = extra[3];
|
||||
|
||||
log_warning("led_bd", "31: %02x = (%02x %02x %02x)", extra[0], extra[1], extra[2], extra[3]);
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x31\x01\x48", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x32:
|
||||
log_warning("led_bd", "32: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
|
||||
extra[4], extra[5], extra[6], extra[7]);
|
||||
|
||||
for (unsigned char i = extra[2] - 1; i < extra[1]; i++) {
|
||||
COLOURS[i][0] = extra[3];
|
||||
COLOURS[i][1] = extra[4];
|
||||
COLOURS[i][2] = extra[5];
|
||||
}
|
||||
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x32\x01\x49", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x33:
|
||||
log_warning("led_bd", "33: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
|
||||
extra[4], extra[5], extra[6], extra[7]);
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x33\x01\x4a", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
COLOURS[extra[0]][0] = extra[extra[5]];
|
||||
COLOURS[extra[0]][1] = extra[extra[6]];
|
||||
COLOURS[extra[0]][2] = extra[extra[7]];
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
log_warning("led_bd", "39: %02x %02x %02x", extra[0], extra[1], extra[2]);
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x39\x01\x50", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
|
||||
COLOURS[9][0] = extra[0];
|
||||
COLOURS[9][1] = extra[0];
|
||||
COLOURS[9][2] = extra[0];
|
||||
break;
|
||||
case 0x3b:
|
||||
log_warning("led_bd", "3b");
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x3b\x01\x52", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x3c:
|
||||
log_warning("led_bd", "3c (I am %ls)", dev->com->wName);
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x3c\x01\x53", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x3f:
|
||||
log_warning("led_bd", "3f: %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
|
||||
extra[4], extra[5], extra[6]);
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x3f\x01\x56", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
case 0x7c:
|
||||
// extra[0] goes from 0 to 7
|
||||
// Could this be some sort of calibration for the buttons?
|
||||
log_warning("led_bd", "7c: %02x", extra[0]);
|
||||
comdev_write(dev, "\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9);
|
||||
// \/ causes 7b to be used
|
||||
// comdev_write(dev, "\xe0\x01\x11\x04\x01\x7c\x01\x10\xa4", 9);
|
||||
// syn dst src len sts op. rep --- chk
|
||||
break;
|
||||
case 0x7b:
|
||||
log_warning("led_bd", "7b: %02x %02x %02x", extra[0], extra[1], extra[2]);
|
||||
comdev_write(dev, "\xe0\x01\x11\x03\x01\x7b\x01\x92", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("led_bd", "Unknown op %02x (%d)", head.op, head.length - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
free(extra);
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI led_null_thread(com_device_t* dev) {
|
||||
while (1) Sleep(10000000);
|
||||
}
|
||||
|
||||
void led_overlay(IDirect3DDevice9* dev) {
|
||||
ShowCursor(true);
|
||||
D3DDEVICE_CREATION_PARAMETERS cparams;
|
||||
RECT rect;
|
||||
|
||||
dev->lpVtbl->GetCreationParameters(dev, &cparams);
|
||||
GetClientRect(cparams.hFocusWindow, &rect);
|
||||
|
||||
if (GetAsyncKeyState(VK_LBUTTON) & 1) {
|
||||
POINT cursor;
|
||||
GetCursorPos(&cursor);
|
||||
|
||||
// log_info("led_overlay", "x: %d, y: %d", cursor.x, cursor.y);
|
||||
log_info("led_overlay", "x%: %f, y%: %f", (float)cursor.x / (float)rect.right,
|
||||
(float)(cursor.y - 26) / (float)rect.bottom);
|
||||
}
|
||||
|
||||
for (unsigned char i = 0; i < 10; i++) {
|
||||
int x = rect.right * positions[i][0];
|
||||
int y = rect.bottom * positions[i][1];
|
||||
draw_rect(dev, x - 25, y - 25, 50, 50, COLOURS[i][0], COLOURS[i][1], COLOURS[i][2]);
|
||||
}
|
||||
}
|
||||
|
||||
void install_led_bd() {
|
||||
register_gui_hook(&led_overlay);
|
||||
|
||||
com_device_t* com5 = new_com_device(5);
|
||||
com_device_thread(com5, led_null_thread);
|
||||
com_device_t* leds_1p = new_com_device(6);
|
||||
com_device_thread(leds_1p, led_bd_thread);
|
||||
com_device_t* com7 = new_com_device(7);
|
||||
com_device_thread(com7, led_null_thread);
|
||||
com_device_t* leds_2p = new_com_device(8);
|
||||
com_device_thread(leds_2p, led_bd_thread);
|
||||
}
|
||||
#include "../hooks/gui.h"
|
||||
#include "_devices.h"
|
||||
|
||||
/*
|
||||
[0] = e0
|
||||
[1] = dest?
|
||||
[2] = dst?
|
||||
[3] = length
|
||||
[4] = op code
|
||||
[...] length-1 bytes
|
||||
[.] = sum
|
||||
|
||||
[0] = e0
|
||||
[2] = dst?
|
||||
[1] = dest?
|
||||
[3] = length
|
||||
[4] = status
|
||||
[5] = op
|
||||
[6] = report
|
||||
[...]
|
||||
[.] = sum
|
||||
|
||||
OP codes:
|
||||
3c: FUN_005735c0 (1)
|
||||
|
||||
10: FUN_00580c00 (1)
|
||||
7c: FUN_00580c00 (2)
|
||||
3c: FUN_00580c00 (1)
|
||||
39: FUN_00580c00 (4)
|
||||
3b: FUN_00580c00 (1)
|
||||
|
||||
31: FUN_00581350 (5)
|
||||
32: FUN_005813b0 (8)
|
||||
33: FUN_00581430 (8) -> something at [16]??
|
||||
39: FUN_005814b0 (4)
|
||||
3f: FUN_00581220 (7)
|
||||
|
||||
7b: FUN_005812a0 (3)
|
||||
7c: FUN_00581310 (2)
|
||||
|
||||
01: was this just an error?
|
||||
10:
|
||||
|
||||
31: Set button. [button] [r] [g] [b]
|
||||
0-7 = buttons
|
||||
8 = woofer
|
||||
9 = center
|
||||
32: Set multiple. [00] [idx hi] [idx lo] [r] [g] [b]
|
||||
33: Fade multiple?. [09] [?] [?] [r] [g] [b]
|
||||
39: Set body light. [intensity] [-] [-]
|
||||
3b:
|
||||
3c: Commit?
|
||||
3f:
|
||||
|
||||
7c:
|
||||
7b:
|
||||
|
||||
initial setup: 7c 0-7, 32, 3c, 39, 3f, 3b
|
||||
*/
|
||||
|
||||
unsigned char COLOURS[10][3];
|
||||
double positions[10][2] = {
|
||||
{ 0.337963, 0.470833 }, { 0.469444, 0.619792 }, { 0.469444, 0.828125 }, { 0.337037, 0.977083 },
|
||||
{ 0.152778, 0.976042 }, { 0.020370, 0.828125 }, { 0.020370, 0.618750 }, { 0.151852, 0.472917 },
|
||||
{ 0.5, 0.75 }, { 0.5, 0.5 },
|
||||
};
|
||||
|
||||
typedef struct rs232c_recv_head {
|
||||
BYTE sync;
|
||||
BYTE src;
|
||||
BYTE dst;
|
||||
BYTE length;
|
||||
BYTE op;
|
||||
} rs232c_recv_head_t;
|
||||
|
||||
BYTE extra[0xff];
|
||||
static DWORD WINAPI led_bd_thread(com_device_t* dev) {
|
||||
log_warning("led_bd", "%ls woke up", dev->com->wName);
|
||||
while (1) {
|
||||
rs232c_recv_head_t head;
|
||||
if (comdev_available(dev) < sizeof head) {
|
||||
// Sleep(100);
|
||||
continue;
|
||||
}
|
||||
comdev_read(dev, (unsigned char*)&head, sizeof head);
|
||||
comdev_read(dev, extra, head.length);
|
||||
|
||||
// log_info("led_bd", "Bound %02x->%02x", head.src, head.dst);
|
||||
|
||||
switch (head.op) {
|
||||
case 0x01:
|
||||
log_warning("led_bd", "01");
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x01\x01\x18", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
log_warning("led_bd", "10");
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x10\x01\x27", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
COLOURS[extra[0]][0] = extra[1];
|
||||
COLOURS[extra[0]][1] = extra[2];
|
||||
COLOURS[extra[0]][2] = extra[3];
|
||||
|
||||
log_warning("led_bd", "31: %02x = (%02x %02x %02x)", extra[0], extra[1], extra[2], extra[3]);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x31\x01\x48", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x32:
|
||||
log_warning("led_bd", "32: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
|
||||
extra[4], extra[5], extra[6], extra[7]);
|
||||
|
||||
for (unsigned char i = extra[2] - 1; i < extra[1]; i++) {
|
||||
COLOURS[i][0] = extra[3];
|
||||
COLOURS[i][1] = extra[4];
|
||||
COLOURS[i][2] = extra[5];
|
||||
}
|
||||
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x32\x01\x49", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x33:
|
||||
log_warning("led_bd", "33: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
|
||||
extra[4], extra[5], extra[6], extra[7]);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x33\x01\x4a", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
COLOURS[extra[0]][0] = extra[extra[5]];
|
||||
COLOURS[extra[0]][1] = extra[extra[6]];
|
||||
COLOURS[extra[0]][2] = extra[extra[7]];
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
log_warning("led_bd", "39: %02x %02x %02x", extra[0], extra[1], extra[2]);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x39\x01\x50", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
|
||||
COLOURS[9][0] = extra[0];
|
||||
COLOURS[9][1] = extra[0];
|
||||
COLOURS[9][2] = extra[0];
|
||||
break;
|
||||
case 0x3b:
|
||||
log_warning("led_bd", "3b");
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3b\x01\x52", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x3c:
|
||||
log_warning("led_bd", "3c (I am %ls)", dev->com->wName);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3c\x01\x53", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
case 0x3f:
|
||||
log_warning("led_bd", "3f: %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
|
||||
extra[4], extra[5], extra[6]);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x3f\x01\x56", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
case 0x7c:
|
||||
// extra[0] goes from 0 to 7
|
||||
// Could this be some sort of calibration for the buttons?
|
||||
log_warning("led_bd", "7c: %02x", extra[0]);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9);
|
||||
// \/ causes 7b to be used
|
||||
// comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x10\xa4", 9);
|
||||
// syn dst src len sts op. rep --- chk
|
||||
break;
|
||||
case 0x7b:
|
||||
log_warning("led_bd", "7b: %02x %02x %02x", extra[0], extra[1], extra[2]);
|
||||
comdev_write(dev, (unsigned char*)"\xe0\x01\x11\x03\x01\x7b\x01\x92", 8);
|
||||
// syn dst src len sts op. rep chk
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("led_bd", "Unknown op %02x (%d)", head.op, head.length - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI led_null_thread(com_device_t* dev) {
|
||||
while (1) Sleep(10000000);
|
||||
}
|
||||
|
||||
void led_overlay(IDirect3DDevice9* dev) {
|
||||
ShowCursor(true);
|
||||
D3DDEVICE_CREATION_PARAMETERS cparams;
|
||||
RECT rect;
|
||||
|
||||
dev->lpVtbl->GetCreationParameters(dev, &cparams);
|
||||
GetClientRect(cparams.hFocusWindow, &rect);
|
||||
|
||||
if (GetAsyncKeyState(VK_LBUTTON) & 1) {
|
||||
POINT cursor;
|
||||
GetCursorPos(&cursor);
|
||||
|
||||
// log_info("led_overlay", "x: %d, y: %d", cursor.x, cursor.y);
|
||||
// log_info("led_overlay", "x%: %f, y%: %f", (float)cursor.x / (float)rect.right,
|
||||
// (float)(cursor.y - 26) / (float)rect.bottom);
|
||||
}
|
||||
|
||||
for (unsigned char i = 0; i < 10; i++) {
|
||||
int x = (int)(rect.right * positions[i][0]);
|
||||
int y = (int)(rect.bottom * positions[i][1]);
|
||||
draw_rect(dev, x - 25, y - 25, 50, 50, COLOURS[i][0], COLOURS[i][1], COLOURS[i][2]);
|
||||
}
|
||||
}
|
||||
|
||||
void install_led_bd() {
|
||||
register_gui_hook(&led_overlay);
|
||||
|
||||
com_device_t* com5 = new_com_device(5);
|
||||
com_device_thread(com5, led_null_thread);
|
||||
com_device_t* leds_1p = new_com_device(6);
|
||||
com_device_thread(leds_1p, led_bd_thread);
|
||||
com_device_t* com7 = new_com_device(7);
|
||||
com_device_thread(com7, led_null_thread);
|
||||
com_device_t* leds_2p = new_com_device(8);
|
||||
com_device_thread(leds_2p, led_bd_thread);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
devices_files = files(
|
||||
'_devices.c',
|
||||
'led_bd.c',
|
||||
'touch_bd.c',
|
||||
devices_files = files(
|
||||
'_devices.c',
|
||||
'led_bd.c',
|
||||
'touch_bd.c',
|
||||
'aime_bd.c',
|
||||
)
|
@ -1,84 +1,84 @@
|
||||
#include "_devices.h"
|
||||
|
||||
static BYTE read_one(com_device_t* dev) {
|
||||
while (!comdev_available(dev)) Sleep(50);
|
||||
BYTE data;
|
||||
comdev_read(dev, (char*)&data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0";
|
||||
static BYTE get_touch_id(BYTE id) {
|
||||
for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) {
|
||||
if (TOUCH_ID_LUT[i] == id) return i;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
BOOL touch_is_enabled = false;
|
||||
BYTE thresh = 0x00; // Lazy caching of single value
|
||||
DWORD WINAPI touch_bd_thread(com_device_t* dev) {
|
||||
while (1) {
|
||||
if (touch_is_enabled && !comdev_available(dev)) {
|
||||
// Active mode!
|
||||
comdev_write(dev, "(@@@@@@@@@@@@)", 14);
|
||||
Sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (read_one(dev) != '{') continue;
|
||||
while (comdev_available(dev) < 5) {
|
||||
log_info("touch", "<. .>");
|
||||
Sleep(50);
|
||||
}
|
||||
BYTE command[5];
|
||||
comdev_read(dev, command, 5);
|
||||
BYTE response[6];
|
||||
memcpy(response, "( )", 6);
|
||||
|
||||
if (memcmp(command, "HALT}", 5) == 0) {
|
||||
if (touch_is_enabled)
|
||||
log_info("touch", "Touchscreen left active mode");
|
||||
else
|
||||
log_misc("touch", "Touchscreen not in active mode");
|
||||
touch_is_enabled = false;
|
||||
} else if (memcmp(command, "STAT}", 5) == 0) {
|
||||
if (!touch_is_enabled)
|
||||
log_info("touch", "Touchscreen entered active mode");
|
||||
else
|
||||
log_misc("touch", "Touchscreen already in active mode");
|
||||
touch_is_enabled = true;
|
||||
} else if (command[2] == 'k' && command[4] == '}') {
|
||||
BYTE sensor = get_touch_id(command[1]);
|
||||
|
||||
log_misc("touch", "k-command recieved: %d >=%d", sensor, command[3]);
|
||||
// Sensor == '@': failed
|
||||
// ( <L/R> <sensor> <> <> )
|
||||
response[1] = command[0];
|
||||
response[2] = command[1];
|
||||
thresh = command[3];
|
||||
|
||||
comdev_write(dev, response, 6);
|
||||
} else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') {
|
||||
BYTE sensor = get_touch_id(command[1]);
|
||||
|
||||
// { <L/R> <sensor> t h }
|
||||
log_misc("touch", "th-command recieved: %d", sensor);
|
||||
|
||||
// Sensor == '@': failed
|
||||
// ( <L/R> <sensor> <> <threshold> )
|
||||
response[1] = command[0]; // 'L' or 'R'
|
||||
response[2] = command[1]; // Sensor
|
||||
response[4] = thresh;
|
||||
|
||||
comdev_write(dev, response, 6);
|
||||
} else {
|
||||
log_error("touch", "Unhandled: {%.*s", 5, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void install_touch_bd() {
|
||||
com_device_t* touch = new_com_device(3);
|
||||
com_device_thread(touch, touch_bd_thread);
|
||||
}
|
||||
#include "_devices.h"
|
||||
|
||||
static BYTE read_one(com_device_t* dev) {
|
||||
while (!comdev_available(dev)) Sleep(50);
|
||||
BYTE data;
|
||||
comdev_read(dev, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0";
|
||||
static BYTE get_touch_id(BYTE id) {
|
||||
for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) {
|
||||
if (TOUCH_ID_LUT[i] == id) return i;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
BOOL touch_is_enabled = false;
|
||||
BYTE thresh = 0x00; // Lazy caching of single value
|
||||
DWORD WINAPI touch_bd_thread(com_device_t* dev) {
|
||||
while (1) {
|
||||
if (touch_is_enabled && !comdev_available(dev)) {
|
||||
// Active mode!
|
||||
comdev_write(dev, (unsigned char*)"(@@@@@@@@@@@@)", 14);
|
||||
Sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (read_one(dev) != '{') continue;
|
||||
while (comdev_available(dev) < 5) {
|
||||
log_info("touch", "<. .>");
|
||||
Sleep(50);
|
||||
}
|
||||
BYTE command[5];
|
||||
comdev_read(dev, command, 5);
|
||||
BYTE response[6];
|
||||
memcpy(response, "( )", 6);
|
||||
|
||||
if (memcmp(command, "HALT}", 5) == 0) {
|
||||
if (touch_is_enabled)
|
||||
log_info("touch", "Touchscreen left active mode");
|
||||
else
|
||||
log_misc("touch", "Touchscreen not in active mode");
|
||||
touch_is_enabled = false;
|
||||
} else if (memcmp(command, "STAT}", 5) == 0) {
|
||||
if (!touch_is_enabled)
|
||||
log_info("touch", "Touchscreen entered active mode");
|
||||
else
|
||||
log_misc("touch", "Touchscreen already in active mode");
|
||||
touch_is_enabled = true;
|
||||
} else if (command[2] == 'k' && command[4] == '}') {
|
||||
BYTE sensor = get_touch_id(command[1]);
|
||||
|
||||
log_misc("touch", "k-command recieved: %d >=%d", sensor, command[3]);
|
||||
// Sensor == '@': failed
|
||||
// ( <L/R> <sensor> <> <> )
|
||||
response[1] = command[0];
|
||||
response[2] = command[1];
|
||||
thresh = command[3];
|
||||
|
||||
comdev_write(dev, response, 6);
|
||||
} else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') {
|
||||
BYTE sensor = get_touch_id(command[1]);
|
||||
|
||||
// { <L/R> <sensor> t h }
|
||||
log_misc("touch", "th-command recieved: %d", sensor);
|
||||
|
||||
// Sensor == '@': failed
|
||||
// ( <L/R> <sensor> <> <threshold> )
|
||||
response[1] = command[0]; // 'L' or 'R'
|
||||
response[2] = command[1]; // Sensor
|
||||
response[4] = thresh;
|
||||
|
||||
comdev_write(dev, response, 6);
|
||||
} else {
|
||||
log_error("touch", "Unhandled: {%.*s", 5, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void install_touch_bd() {
|
||||
com_device_t* touch = new_com_device(3);
|
||||
com_device_thread(touch, touch_bd_thread);
|
||||
}
|
||||
|
@ -1,86 +1,95 @@
|
||||
#include "common.h"
|
||||
#include "devices/_devices.h"
|
||||
#include "drivers/mx.h"
|
||||
#include "hooks/_hooks.h"
|
||||
|
||||
WCHAR exePath[MAX_PATH + 1];
|
||||
|
||||
void enable_traces() {
|
||||
patches_t patches;
|
||||
char error[256];
|
||||
if (!load_patches(&patches, "patches.json", error)) {
|
||||
log_error(BOOT_LOGGER, "Failed to load patches file: %s", error);
|
||||
} else {
|
||||
char exePathC[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL);
|
||||
|
||||
for (size_t i = 0; i < patches.nopatchsets; i++) {
|
||||
patchset_t* patchset = patches.patchsets[i];
|
||||
|
||||
// Require the binary explicitly named
|
||||
if (patchset->binary_name == NULL || strcmp(patchset->binary_name, exePathC) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (!patchset->apply) continue;
|
||||
|
||||
for (size_t j = 0; j < patchset->nopatches; j++) {
|
||||
patch_t patch = patchset->patches[j];
|
||||
|
||||
if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) {
|
||||
log_error(BOOT_LOGGER, "Patch %s[%d] failed! from-value missmatch", patchset->name, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy((void*)patch.offset, patch.to, patch.count);
|
||||
log_misc(BOOT_LOGGER, "Patched %d bytes at %08x", patch.count, patch.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
free_patches(&patches);
|
||||
}
|
||||
|
||||
void prebind_hooks() {
|
||||
hook_all();
|
||||
install_devices();
|
||||
|
||||
// TODO: Figure out why we're needing to call this manually (medium priority)
|
||||
if (wcscmp(exePath, L"ALLNetProc.exe") == 0) {
|
||||
// OPENSSL_add_all_algorithms_noconf
|
||||
((void (*)(void))(0x00459770))();
|
||||
}
|
||||
}
|
||||
|
||||
void init_injection() {
|
||||
// We're in a new context now, so need to reconfigure
|
||||
setup_logging();
|
||||
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath);
|
||||
|
||||
enable_traces();
|
||||
|
||||
setup_columba();
|
||||
setup_mxsram();
|
||||
setup_mxsuperio();
|
||||
setup_mxjvs();
|
||||
setup_mxhwreset();
|
||||
setup_mxsmbus();
|
||||
|
||||
if (!add_fake_device(&PLATFORM_GUID, L"\\\\.\\platform")) {
|
||||
log_error("platform", "failed to install platform device");
|
||||
}
|
||||
|
||||
// Must be the last thing called!
|
||||
// register_devices();
|
||||
prebind_hooks();
|
||||
setup_hooks();
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
|
||||
|
||||
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
||||
wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath));
|
||||
|
||||
init_injection();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#include "common.h"
|
||||
#include "devices/_devices.h"
|
||||
#include "drivers/mx.h"
|
||||
#include "hooks/_hooks.h"
|
||||
|
||||
WCHAR exePath[MAX_PATH + 1];
|
||||
|
||||
void enable_traces() {
|
||||
patches_t patches;
|
||||
char error[256];
|
||||
if (!load_patches(&patches, "patches.json", error)) {
|
||||
log_error(BOOT_LOGGER, "Failed to load patches file: %s", error);
|
||||
} else {
|
||||
char exePathC[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL);
|
||||
|
||||
for (size_t i = 0; i < patches.nopatchsets; i++) {
|
||||
patchset_t* patchset = patches.patchsets[i];
|
||||
|
||||
// Require the binary explicitly named
|
||||
if (patchset->binary_name == NULL || strcmp(patchset->binary_name, exePathC) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (!patchset->apply) continue;
|
||||
|
||||
for (size_t j = 0; j < patchset->nopatches; j++) {
|
||||
patch_t patch = patchset->patches[j];
|
||||
|
||||
if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) {
|
||||
log_error(BOOT_LOGGER, "Patch %s[%d] failed! from-value missmatch", patchset->name, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy((void*)patch.offset, patch.to, patch.count);
|
||||
log_misc(BOOT_LOGGER, "Patched %d bytes at %08x", patch.count, patch.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
free_patches(&patches);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void prebind_hooks() {
|
||||
hook_all();
|
||||
install_devices();
|
||||
// TODO: Figure out why we're needing to call this manually (medium priority)
|
||||
if (wcscmp(exePath, L"ALLNetProc.exe") == 0) {
|
||||
log_warning(BOOT_LOGGER, "Making explicit call to OPENSSL_add_all_algorithms_noconf");
|
||||
|
||||
// OPENSSL_add_all_algorithms_noconf
|
||||
((void (*)(void))(0x00459770))();
|
||||
}
|
||||
}
|
||||
|
||||
void init_injection() {
|
||||
// We're in a new context now, so need to reconfigure
|
||||
setup_logging();
|
||||
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath);
|
||||
|
||||
enable_traces();
|
||||
|
||||
// Columba: Driver-level memory access, used to read the DMI tables
|
||||
setup_columba();
|
||||
// MX SRAM: SRAM-based nv memory
|
||||
setup_mxsram();
|
||||
// MX SuperIO: Communicate with the HW monitor chip
|
||||
setup_mxsuperio();
|
||||
// MX JVS: Interacting with JVS-based devices
|
||||
setup_mxjvs();
|
||||
// MX HW Reset: Forcibly reboot the machine
|
||||
setup_mxhwreset();
|
||||
// MX SMBus: Communicate over the LPC bus. This contains the EEPROM, and PCA9535
|
||||
setup_mxsmbus();
|
||||
|
||||
if (!add_fake_device(&PLATFORM_GUID, L"\\\\.\\platform")) {
|
||||
log_error("platform", "failed to install platform device");
|
||||
}
|
||||
|
||||
// Must be the last thing called!
|
||||
// register_devices();
|
||||
prebind_hooks();
|
||||
setup_hooks();
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
|
||||
|
||||
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
||||
wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath));
|
||||
|
||||
init_injection();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1,73 +1,73 @@
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "mx.h"
|
||||
|
||||
// Much easier than pulling in winddk.h
|
||||
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
|
||||
typedef struct {
|
||||
PHYSICAL_ADDRESS addr;
|
||||
DWORD data_type;
|
||||
DWORD bytes;
|
||||
} columba_request;
|
||||
|
||||
#define DMI_HEADER_START 0x000f0000
|
||||
#define DMI_TABLES_START 0x000f1000
|
||||
|
||||
BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_COLUMBA_READ_DMI:
|
||||
log_misc("columba",
|
||||
"DeviceIoControl(<columba>, <read dmi>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
columba_request* request = (columba_request*)lpInBuffer;
|
||||
log_info("columba", "Physical read: 0x%04x %ss at %08X", request->bytes,
|
||||
request->data_type == 1 ? "byte"
|
||||
: request->data_type == 2 ? "short"
|
||||
: request->data_type == 4 ? "long"
|
||||
: "void",
|
||||
request->addr);
|
||||
DWORD requested_size = request->data_type * request->bytes;
|
||||
|
||||
memset(lpOutBuffer, 0, nOutBufferSize);
|
||||
|
||||
if (request->addr.QuadPart == DMI_HEADER_START) {
|
||||
DMI_HEADER dmi = {
|
||||
.Signature = { '_', 'D', 'M', 'I', '_' },
|
||||
.Checksum = 0,
|
||||
.StructLength = dmi_size,
|
||||
.StructAddr = DMI_TABLES_START,
|
||||
.NumberOfStructs = 0x20,
|
||||
.BCDRevision = 0,
|
||||
.Reserved = 0,
|
||||
};
|
||||
dmi.Checksum = dmi_calc_checksum((char*)&dmi, 15);
|
||||
|
||||
memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER));
|
||||
if (lpBytesReturned) *lpBytesReturned = requested_size;
|
||||
} else if (request->addr.QuadPart == DMI_TABLES_START) {
|
||||
memcpy(lpOutBuffer, dmi_table, dmi_size);
|
||||
if (lpBytesReturned) *lpBytesReturned = 0x10000;
|
||||
} else {
|
||||
log_error("columna", "Request to unmapped memory location: %08x", request->addr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
log_warning("columba", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_columba() {
|
||||
dmi_build_default();
|
||||
|
||||
file_hook_t* columba = new_file_hook(L"\\\\.\\columba");
|
||||
columba->DeviceIoControl = &columba_DeviceIoControl;
|
||||
|
||||
hook_file(columba);
|
||||
}
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "mx.h"
|
||||
|
||||
// Much easier than pulling in winddk.h
|
||||
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
|
||||
typedef struct {
|
||||
PHYSICAL_ADDRESS addr;
|
||||
DWORD data_type;
|
||||
DWORD bytes;
|
||||
} columba_request;
|
||||
|
||||
#define DMI_HEADER_START 0x000f0000
|
||||
#define DMI_TABLES_START 0x000f1000
|
||||
|
||||
BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_COLUMBA_READ:
|
||||
log_misc("columba", "DeviceIoControl(<columba>, <read>, 0x%p, 0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
columba_request* request = (columba_request*)lpInBuffer;
|
||||
log_info("columba", "Physical read: 0x%04x %ss at %08X", request->bytes,
|
||||
request->data_type == 1 ? "byte"
|
||||
: request->data_type == 2 ? "short"
|
||||
: request->data_type == 4 ? "long"
|
||||
: "void",
|
||||
request->addr);
|
||||
DWORD requested_size = request->data_type * request->bytes;
|
||||
|
||||
memset(lpOutBuffer, 0, nOutBufferSize);
|
||||
|
||||
if (request->addr.QuadPart == DMI_HEADER_START) {
|
||||
DMI_HEADER dmi = {
|
||||
.Signature = { '_', 'D', 'M', 'I', '_' },
|
||||
.Checksum = 0,
|
||||
.StructLength = dmi_size,
|
||||
.StructAddr = DMI_TABLES_START,
|
||||
.NumberOfStructs = 0x20,
|
||||
.BCDRevision = 0,
|
||||
.Reserved = 0,
|
||||
};
|
||||
dmi.Checksum = dmi_calc_checksum((char*)&dmi, 15);
|
||||
|
||||
memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER));
|
||||
if (lpBytesReturned) *lpBytesReturned = requested_size;
|
||||
} else if (request->addr.QuadPart == DMI_TABLES_START) {
|
||||
memcpy(lpOutBuffer, dmi_table, dmi_size);
|
||||
if (lpBytesReturned) *lpBytesReturned = 0x10000;
|
||||
} else {
|
||||
log_error("columba", "Request to unmapped memory location: %08x",
|
||||
request->addr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// Observed: IOCTL_KSEC_RNG_REKEY
|
||||
log_warning("columba", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_columba() {
|
||||
dmi_build_default();
|
||||
|
||||
file_hook_t* columba = new_file_hook(L"\\\\.\\columba");
|
||||
columba->DeviceIoControl = &columba_DeviceIoControl;
|
||||
|
||||
hook_file(columba);
|
||||
}
|
||||
|
@ -1,27 +1,25 @@
|
||||
#pragma once
|
||||
#include "../hooks/_hooks.h"
|
||||
#include "../common.h"
|
||||
|
||||
FnDeviceIoControl mxhwreset_DeviceIoControl;
|
||||
void setup_mxhwreset();
|
||||
|
||||
FnDeviceIoControl mxjvs_DeviceIoControl;
|
||||
void setup_mxjvs();
|
||||
|
||||
FnDeviceIoControl mxsmbus_DeviceIoControl;
|
||||
void setup_mxsmbus();
|
||||
|
||||
FnDeviceIoControl mxsram_DeviceIoControl;
|
||||
FnSetFilePointer mxsram_SetFilePointer;
|
||||
FnWriteFile mxsram_WriteFile;
|
||||
FnReadFile mxsram_ReadFile;
|
||||
void setup_mxsram();
|
||||
|
||||
FnDeviceIoControl mxsuperio_DeviceIoControl;
|
||||
void setup_mxsuperio();
|
||||
|
||||
FnDeviceIoControl columba_DeviceIoControl;
|
||||
void setup_columba();
|
||||
|
||||
DEFINE_GUID(MXSMBUS_GUID, 0x5C49E1FE, 0x3FEC, 0x4B8D, 0xA4, 0xB5, 0x76, 0xBE, 0x70, 0x25, 0xD8, 0x42);
|
||||
DEFINE_GUID(PLATFORM_GUID, 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3e, 0x30, 0x1F, 0x73);
|
||||
#pragma once
|
||||
#include "../hooks/_hooks.h"
|
||||
#include "../common.h"
|
||||
#include "../../lib/am/amEeprom.h"
|
||||
|
||||
FnDeviceIoControl mxhwreset_DeviceIoControl;
|
||||
void setup_mxhwreset();
|
||||
|
||||
FnDeviceIoControl mxjvs_DeviceIoControl;
|
||||
void setup_mxjvs();
|
||||
|
||||
FnDeviceIoControl mxsmbus_DeviceIoControl;
|
||||
void setup_mxsmbus();
|
||||
|
||||
FnDeviceIoControl mxsram_DeviceIoControl;
|
||||
FnSetFilePointer mxsram_SetFilePointer;
|
||||
FnWriteFile mxsram_WriteFile;
|
||||
FnReadFile mxsram_ReadFile;
|
||||
void setup_mxsram();
|
||||
|
||||
FnDeviceIoControl mxsuperio_DeviceIoControl;
|
||||
void setup_mxsuperio();
|
||||
|
||||
FnDeviceIoControl columba_DeviceIoControl;
|
||||
void setup_columba();
|
||||
|
@ -1,377 +1,394 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../common.h"
|
||||
#include "jvs.h"
|
||||
#include "mx.h"
|
||||
|
||||
BOOL JVS_SENSE = false;
|
||||
BOOL coin_solenoid = false;
|
||||
BOOL test_btn = false;
|
||||
|
||||
// #define SCAN_COIN 0x70
|
||||
#define SCAN_TEST VK_OEM_4 // [{
|
||||
// 2 Players, 16 buttons each
|
||||
int jvs_buttons[2][16] = {
|
||||
{
|
||||
'C', // *1P3
|
||||
'P', // NC
|
||||
'E', // *1P1
|
||||
'D', // *1P2
|
||||
'P', // NC
|
||||
'P', // NC
|
||||
'1', // *1P Service
|
||||
'P', // NC
|
||||
'P', // --
|
||||
'P', // --
|
||||
'P', // --
|
||||
'W', // *1P8
|
||||
'Q', // *1P7
|
||||
'A', // *1P6
|
||||
'Z', // *1P5
|
||||
'X', // *1P4
|
||||
},
|
||||
{
|
||||
VK_OEM_PERIOD, // *2P3
|
||||
'P', // NC
|
||||
'O', // *2P1
|
||||
'L', // *2P2
|
||||
'P', // NC
|
||||
'P', // NC
|
||||
'2', // *2P Service
|
||||
'P', // NC
|
||||
'P', // --
|
||||
'P', // --
|
||||
'P', // --
|
||||
'I', // *2P8
|
||||
'U', // *2P7
|
||||
'J', // *2P6
|
||||
'M', // *2P5
|
||||
VK_OEM_COMMA, // *2P4
|
||||
},
|
||||
};
|
||||
|
||||
short jvs_unpad(char* paddedData, short length, char* unpaddedData) {
|
||||
short index = 0;
|
||||
bool escape = false;
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (escape)
|
||||
unpaddedData[index++] = paddedData[i] + 1;
|
||||
else if (paddedData[i] == JVS_MARK)
|
||||
escape = true;
|
||||
else
|
||||
unpaddedData[index++] = paddedData[i];
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
short jvs_pad(char* unpaddedData, short length, char* paddedData, short paddedMax) {
|
||||
short index = 0;
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (i > paddedMax) return -1;
|
||||
|
||||
if (unpaddedData[i] == JVS_MARK || unpaddedData[i] == JVS_SYNC) {
|
||||
paddedData[index++] = JVS_MARK;
|
||||
paddedData[index++] = unpaddedData[i] - 1;
|
||||
} else {
|
||||
paddedData[index++] = unpaddedData[i];
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
const char JVS_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
|
||||
|
||||
void mxjvs_exchange(char* paddedIn, short inCount, char* outData, int maxOut, int* outCount) {
|
||||
unsigned char* inData = malloc(inCount);
|
||||
inCount = jvs_unpad(paddedIn, inCount, inData);
|
||||
unsigned char* response = malloc(maxOut);
|
||||
|
||||
unsigned char status = JVS_STATUS_OK;
|
||||
|
||||
// JVS frame is 4 bytes in total
|
||||
if (inCount < 4) {
|
||||
log_error("mxjvs", "inCount impossibly small: %d", inCount);
|
||||
status = JVS_STATUS_UNKNOWN;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
// This isn't a JVS packet
|
||||
if (inData[0] != JVS_SYNC) {
|
||||
log_error("mxjvs", "SYNC missing. Saw 0x%02x", inData[0]);
|
||||
status = JVS_STATUS_UNKNOWN;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
|
||||
// Validate the checksum before proceeding
|
||||
unsigned char sum = 0;
|
||||
for (int i = 1; i < inCount - 1; i++) sum += inData[i];
|
||||
if (sum != inData[inCount - 1]) {
|
||||
log_error("mxjvs", "Checksum failed. Computed 0x%02x, expected 0x%02x", sum, inData[inCount - 1]);
|
||||
status = JVS_STATUS_SUM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
|
||||
unsigned char destination = inData[1];
|
||||
unsigned char length = inData[2];
|
||||
// length 0 is nonsensical because there's a checksum!
|
||||
if (length == 0) {
|
||||
status = JVS_STATUS_SUM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
short jvsIndex = 3; // D0
|
||||
|
||||
response[0] = JVS_SYNC;
|
||||
response[1] = JVS_NODE_MASTER;
|
||||
short respIndex = 4; // D0
|
||||
#define jvs_read(x) \
|
||||
if (jvsIndex - 2 >= length) { \
|
||||
status = JVS_STATUS_OVERFLOW; \
|
||||
goto jvs_exchange_error; \
|
||||
} else { \
|
||||
(x) = inData[jvsIndex++]; \
|
||||
}
|
||||
#define jvs_write(x) response[respIndex++] = (x);
|
||||
|
||||
while (jvsIndex - 2 < length) {
|
||||
unsigned char cmd;
|
||||
jvs_read(cmd);
|
||||
// log_info("jvs", "jvs cmd: %02x", cmd);
|
||||
switch (cmd) {
|
||||
case JVS_CMD_RESET:
|
||||
unsigned char reset_assert;
|
||||
jvs_read(reset_assert);
|
||||
if (reset_assert != JVS_CMD_RESET_ASSERT) {
|
||||
status = JVS_STATUS_UKCOM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
JVS_SENSE = true;
|
||||
// Special case
|
||||
*outCount = 0;
|
||||
return;
|
||||
case JVS_CMD_CHANGE_COMMS:
|
||||
// Special case
|
||||
*outCount = 0;
|
||||
return;
|
||||
|
||||
case JVS_CMD_ASSIGN_ADDR:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
JVS_SENSE = false;
|
||||
// we don't bother remembering the address because at the moment we only simulate
|
||||
// a single board in the JVS chain.
|
||||
unsigned char _;
|
||||
jvs_read(_);
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_ID:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
for (int i = 0; i < sizeof JVS_ID; i++) jvs_write(JVS_ID[i]);
|
||||
break;
|
||||
case JVS_CMD_GET_CMD_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_CMD);
|
||||
break;
|
||||
case JVS_CMD_GET_JVS_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_JVS);
|
||||
break;
|
||||
case JVS_CMD_GET_COMM_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_COMM);
|
||||
break;
|
||||
|
||||
case JVS_CMD_GET_FEATURES:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
|
||||
jvs_write(JVS_FEATURE_PLAYERS);
|
||||
jvs_write(2);
|
||||
jvs_write(13);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_COINS);
|
||||
jvs_write(2);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_ANALOG);
|
||||
jvs_write(8); // 8 ADC channels
|
||||
jvs_write(JVS_FEATURE_PAD); // ?? (was "10" prior)
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_GPIO);
|
||||
jvs_write(6); // 6 ports
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
|
||||
jvs_write(JVS_FEATURE_EOF);
|
||||
|
||||
break;
|
||||
case JVS_CMD_RECEIVE_MAIN_ID:
|
||||
unsigned char tempRead = -1;
|
||||
while (tempRead != 0) jvs_read(tempRead);
|
||||
// TODO: Do we need to report here?
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_SW:
|
||||
unsigned char players;
|
||||
unsigned char switch_bytes;
|
||||
jvs_read(players);
|
||||
jvs_read(switch_bytes);
|
||||
if (players > 2 || switch_bytes != 2) {
|
||||
jvs_write(JVS_REPORT_PARAM_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char buttons = 0x00;
|
||||
if (GetAsyncKeyState(SCAN_TEST) < 0) buttons |= 0x80;
|
||||
jvs_write(buttons);
|
||||
|
||||
for (int i = 0; i < players; i++) {
|
||||
for (int j = 0; j < switch_bytes; j++) {
|
||||
buttons = 0x00;
|
||||
for (int bit = 0; bit < 8; bit++) {
|
||||
int scancode = jvs_buttons[i][j * 8 + bit];
|
||||
|
||||
// Buttons on maimai use beam interrupt sensors, so logical high = unpressed.
|
||||
bool invert = ((j == 0 && (bit == 0 || bit == 2 || bit == 3)) || (j == 1 && bit >= 3));
|
||||
|
||||
if (invert)
|
||||
buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
|
||||
else
|
||||
buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
|
||||
|
||||
// JAMMA does **NOT** do any of this lol
|
||||
// Service is pull-down for some reason
|
||||
// bool pulse = (j == 0) && (bit == 6);
|
||||
// // JAMMA uses the falling edge of a pull-up switch
|
||||
// if (pulse) {
|
||||
// buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
|
||||
// buttons |= (!(GetAsyncKeyState(scancode) & 1)) << bit;
|
||||
// } else {
|
||||
// buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
|
||||
// buttons |= (GetAsyncKeyState(scancode) & 1) << bit;
|
||||
// }
|
||||
}
|
||||
jvs_write(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
// TODO: Actually emulate these (super low priority)
|
||||
unsigned char analog_count;
|
||||
jvs_read(analog_count);
|
||||
for (int i = analog_count; i > 0; i--) {
|
||||
jvs_write(0xde);
|
||||
jvs_write(0xad);
|
||||
}
|
||||
break;
|
||||
|
||||
case JVS_CMD_WRITE_GPIO1:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char gpio_bytes;
|
||||
jvs_read(gpio_bytes);
|
||||
for (int i = 0; i < gpio_bytes; i++) {
|
||||
unsigned char gpio_value;
|
||||
jvs_read(gpio_value);
|
||||
|
||||
if (i == 0) {
|
||||
if (!!(gpio_value & 0x80) != coin_solenoid) {
|
||||
coin_solenoid = !!(gpio_value & 0x80);
|
||||
log_info("mxjvs", "Coin solenoid: %s", coin_solenoid ? "Locked" : "Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
// log_warning("mxjvs", "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxjvs", "Unknown command: 0x%02x", cmd);
|
||||
|
||||
status = JVS_STATUS_UKCOM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
}
|
||||
#undef jvs_read
|
||||
#undef jvs_write
|
||||
|
||||
goto jvs_exchange_complete;
|
||||
jvs_exchange_error:
|
||||
log_error("mxjvs", "JVS status: 0x%02x", status);
|
||||
respIndex = 4; // As if we've just written status, but nothing else
|
||||
|
||||
jvs_exchange_complete:
|
||||
response[2] = respIndex - 2; // respIndex doesn't include SUM yet
|
||||
response[3] = status;
|
||||
|
||||
// Compute and set the checksum
|
||||
sum = 0;
|
||||
for (int i = 1; i < respIndex; i++) sum += response[i];
|
||||
response[respIndex++] = sum;
|
||||
|
||||
short paddedLength = jvs_pad(response, respIndex, outData, maxOut);
|
||||
// We failed hard. It's not worth sending an overflow response
|
||||
if (paddedLength == -1)
|
||||
*outCount = 0;
|
||||
else
|
||||
*outCount = 0x00000000 | paddedLength;
|
||||
|
||||
free(response);
|
||||
free(inData);
|
||||
}
|
||||
|
||||
BOOL mxjvs_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXJVS_EXCHANGE:
|
||||
log_misc("mxjvs",
|
||||
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize, lpBytesReturned);
|
||||
|
||||
break;
|
||||
default:
|
||||
log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxjvs_SetupComm(void* com, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
|
||||
BOOL mxjvs_PurgeComm(void* com, DWORD dwFlags) { return TRUE; }
|
||||
BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
|
||||
|
||||
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
|
||||
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
|
||||
char PARITY[] = { 'N', 'O', 'E', 'M', 'S' };
|
||||
char* STOP[] = { "1", "1.5", "2" };
|
||||
log_info("mxjvs", "Switching to %d baud (%d%c%s)", lpDCB->BaudRate, lpDCB->ByteSize, PARITY[lpDCB->Parity],
|
||||
STOP[lpDCB->StopBits]);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxjvs() {
|
||||
file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs");
|
||||
mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl;
|
||||
|
||||
com_hook_t* jvscom = new_com_hook(-1);
|
||||
jvscom->GetCommState = mxjvs_GetCommState;
|
||||
jvscom->SetCommState = mxjvs_SetCommState;
|
||||
jvscom->SetCommTimeouts = mxjvs_SetCommTimeouts;
|
||||
jvscom->SetupComm = mxjvs_SetupComm;
|
||||
jvscom->PurgeComm = mxjvs_PurgeComm;
|
||||
jvscom->GetCommModemStatus = mxjvs_GetCommModemStatus;
|
||||
|
||||
hook_file(mxjvs);
|
||||
hook_com(jvscom);
|
||||
free(jvscom->virtual_handle);
|
||||
jvscom->virtual_handle = mxjvs->virtual_handle;
|
||||
}
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../common.h"
|
||||
#include "jvs.h"
|
||||
#include "mx.h"
|
||||
|
||||
BOOL JVS_SENSE = false;
|
||||
BOOL coin_solenoid = false;
|
||||
BOOL test_btn = false;
|
||||
|
||||
// #define SCAN_COIN 0x70
|
||||
#define SCAN_TEST VK_OEM_4 // [{
|
||||
// 2 Players, 16 buttons each
|
||||
int jvs_buttons[2][16] = {
|
||||
{
|
||||
'C', // *1P3
|
||||
'P', // NC
|
||||
'E', // *1P1
|
||||
'D', // *1P2
|
||||
'P', // NC
|
||||
'P', // NC
|
||||
'1', // *1P Service
|
||||
'P', // NC
|
||||
'P', // --
|
||||
'P', // --
|
||||
'P', // --
|
||||
'W', // *1P8
|
||||
'Q', // *1P7
|
||||
'A', // *1P6
|
||||
'Z', // *1P5
|
||||
'X', // *1P4
|
||||
},
|
||||
{
|
||||
VK_OEM_PERIOD, // *2P3
|
||||
'P', // NC
|
||||
'O', // *2P1
|
||||
'L', // *2P2
|
||||
'P', // NC
|
||||
'P', // NC
|
||||
'2', // *2P Service
|
||||
'P', // NC
|
||||
'P', // --
|
||||
'P', // --
|
||||
'P', // --
|
||||
'I', // *2P8
|
||||
'U', // *2P7
|
||||
'J', // *2P6
|
||||
'M', // *2P5
|
||||
VK_OEM_COMMA, // *2P4
|
||||
},
|
||||
};
|
||||
|
||||
short jvs_unpad(unsigned char* paddedData, short length, unsigned char* unpaddedData) {
|
||||
short index = 0;
|
||||
bool escape = false;
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (escape)
|
||||
unpaddedData[index++] = paddedData[i] + 1;
|
||||
else if (paddedData[i] == JVS_MARK)
|
||||
escape = true;
|
||||
else
|
||||
unpaddedData[index++] = paddedData[i];
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
short jvs_pad(unsigned char* unpaddedData, short length, unsigned char* paddedData,
|
||||
short paddedMax) {
|
||||
short index = 0;
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (i > paddedMax) return -1;
|
||||
|
||||
if (i != 0 && (unpaddedData[i] == JVS_MARK || unpaddedData[i] == JVS_SYNC)) {
|
||||
paddedData[index++] = JVS_MARK;
|
||||
paddedData[index++] = unpaddedData[i] - 1;
|
||||
} else {
|
||||
paddedData[index++] = unpaddedData[i];
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
const char JVS_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
|
||||
|
||||
void mxjvs_exchange(unsigned char* paddedIn, short inCount, unsigned char* outData, short maxOut,
|
||||
int* outCount) {
|
||||
unsigned char* inData = malloc(inCount);
|
||||
inCount = jvs_unpad(paddedIn, inCount, inData);
|
||||
unsigned char* response = malloc(maxOut);
|
||||
|
||||
unsigned char status = JVS_STATUS_OK;
|
||||
|
||||
// JVS frame is 4 bytes in total
|
||||
if (inCount < 4) {
|
||||
log_error("mxjvs", "inCount impossibly small: %d", inCount);
|
||||
status = JVS_STATUS_UNKNOWN;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
// This isn't a JVS packet
|
||||
if (inData[0] != JVS_SYNC) {
|
||||
log_error("mxjvs", "SYNC missing. Saw 0x%02x", inData[0]);
|
||||
status = JVS_STATUS_UNKNOWN;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
|
||||
// Validate the checksum before proceeding
|
||||
unsigned char sum = 0;
|
||||
for (int i = 1; i < inCount - 1; i++) sum += inData[i];
|
||||
if (sum != inData[inCount - 1]) {
|
||||
log_error("mxjvs", "Checksum failed. Computed 0x%02x, expected 0x%02x", sum,
|
||||
inData[inCount - 1]);
|
||||
status = JVS_STATUS_SUM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
|
||||
unsigned char destination = inData[1];
|
||||
unsigned char length = inData[2];
|
||||
// length 0 is nonsensical because there's a checksum!
|
||||
if (length == 0) {
|
||||
status = JVS_STATUS_SUM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
short jvsIndex = 3; // D0
|
||||
|
||||
response[0] = JVS_SYNC;
|
||||
response[1] = JVS_NODE_MASTER;
|
||||
short respIndex = 4; // D0
|
||||
#define jvs_read(x) \
|
||||
if (jvsIndex - 2 >= length) { \
|
||||
status = JVS_STATUS_OVERFLOW; \
|
||||
goto jvs_exchange_error; \
|
||||
} else { \
|
||||
(x) = inData[jvsIndex++]; \
|
||||
}
|
||||
#define jvs_write(x) response[respIndex++] = (x);
|
||||
|
||||
while (jvsIndex - 2 < length) {
|
||||
unsigned char cmd;
|
||||
jvs_read(cmd);
|
||||
// log_info("jvs", "jvs cmd: %02x", cmd);
|
||||
switch (cmd) {
|
||||
case JVS_CMD_RESET:
|
||||
unsigned char reset_assert;
|
||||
jvs_read(reset_assert);
|
||||
if (reset_assert != JVS_CMD_RESET_ASSERT) {
|
||||
status = JVS_STATUS_UKCOM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
JVS_SENSE = true;
|
||||
// Special case
|
||||
*outCount = 0;
|
||||
return;
|
||||
case JVS_CMD_CHANGE_COMMS:
|
||||
// Special case
|
||||
*outCount = 0;
|
||||
return;
|
||||
|
||||
case JVS_CMD_ASSIGN_ADDR:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
JVS_SENSE = false;
|
||||
// we don't bother remembering the address because at the moment we only simulate
|
||||
// a single board in the JVS chain.
|
||||
unsigned char _;
|
||||
jvs_read(_);
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_ID:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
for (int i = 0; i < sizeof JVS_ID; i++) jvs_write(JVS_ID[i]);
|
||||
break;
|
||||
case JVS_CMD_GET_CMD_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_CMD);
|
||||
break;
|
||||
case JVS_CMD_GET_JVS_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_JVS);
|
||||
break;
|
||||
case JVS_CMD_GET_COMM_VERSION:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
jvs_write(JVS_VERSION_COMM);
|
||||
break;
|
||||
|
||||
case JVS_CMD_GET_FEATURES:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
|
||||
jvs_write(JVS_FEATURE_PLAYERS);
|
||||
jvs_write(2);
|
||||
jvs_write(13);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_COINS);
|
||||
jvs_write(2);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_ANALOG);
|
||||
jvs_write(8); // 8 ADC channels
|
||||
jvs_write(JVS_FEATURE_PAD); // ?? (was "10" prior)
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_GPIO);
|
||||
jvs_write(6); // 6 ports
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
jvs_write(JVS_FEATURE_PAD);
|
||||
|
||||
jvs_write(JVS_FEATURE_EOF);
|
||||
|
||||
break;
|
||||
case JVS_CMD_RECEIVE_MAIN_ID:
|
||||
unsigned char tempRead = 0xff;
|
||||
while (tempRead != 0) jvs_read(tempRead);
|
||||
// TODO: Do we need to report here?
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_SW:
|
||||
unsigned char players;
|
||||
unsigned char switch_bytes;
|
||||
jvs_read(players);
|
||||
jvs_read(switch_bytes);
|
||||
if (players > 2 || switch_bytes != 2) {
|
||||
jvs_write(JVS_REPORT_PARAM_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char buttons = 0x00;
|
||||
if (GetAsyncKeyState(SCAN_TEST) < 0) buttons |= 0x80;
|
||||
jvs_write(buttons);
|
||||
|
||||
for (int i = 0; i < players; i++) {
|
||||
for (int j = 0; j < switch_bytes; j++) {
|
||||
buttons = 0x00;
|
||||
for (int bit = 0; bit < 8; bit++) {
|
||||
int scancode = jvs_buttons[i][j * 8 + bit];
|
||||
|
||||
// Buttons on maimai use beam interrupt sensors, so logical high =
|
||||
// unpressed.
|
||||
bool invert = ((j == 0 && (bit == 0 || bit == 2 || bit == 3)) ||
|
||||
(j == 1 && bit >= 3));
|
||||
|
||||
if (invert)
|
||||
buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
|
||||
else
|
||||
buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
|
||||
|
||||
// JAMMA does **NOT** do any of this lol
|
||||
// Service is pull-down for some reason
|
||||
// bool pulse = (j == 0) && (bit == 6);
|
||||
// // JAMMA uses the falling edge of a pull-up switch
|
||||
// if (pulse) {
|
||||
// buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
|
||||
// buttons |= (!(GetAsyncKeyState(scancode) & 1)) << bit;
|
||||
// } else {
|
||||
// buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
|
||||
// buttons |= (GetAsyncKeyState(scancode) & 1) << bit;
|
||||
// }
|
||||
}
|
||||
jvs_write(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_COIN:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char coin_count;
|
||||
jvs_read(coin_count);
|
||||
for (; coin_count; coin_count--) {
|
||||
jvs_write(0x00); // coin MSB
|
||||
jvs_write(0x00); // coin LSB
|
||||
}
|
||||
break;
|
||||
|
||||
case JVS_CMD_READ_ANALOGS:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
// TODO: Actually emulate these (super low priority)
|
||||
unsigned char analog_count;
|
||||
jvs_read(analog_count);
|
||||
for (int i = analog_count; i > 0; i--) {
|
||||
jvs_write(0xde);
|
||||
jvs_write(0xad);
|
||||
}
|
||||
break;
|
||||
|
||||
case JVS_CMD_WRITE_GPIO1:
|
||||
jvs_write(JVS_REPORT_OK);
|
||||
unsigned char gpio_bytes;
|
||||
jvs_read(gpio_bytes);
|
||||
for (int i = 0; i < gpio_bytes; i++) {
|
||||
unsigned char gpio_value;
|
||||
jvs_read(gpio_value);
|
||||
|
||||
if (i == 0) {
|
||||
if (!!(gpio_value & 0x80) != coin_solenoid) {
|
||||
coin_solenoid = !!(gpio_value & 0x80);
|
||||
log_info("mxjvs", "Coin solenoid: %s",
|
||||
coin_solenoid ? "Locked" : "Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
// log_warning("mxjvs", "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxjvs", "Unknown command: 0x%02x", cmd);
|
||||
|
||||
status = JVS_STATUS_UKCOM;
|
||||
goto jvs_exchange_error;
|
||||
}
|
||||
}
|
||||
#undef jvs_read
|
||||
#undef jvs_write
|
||||
|
||||
goto jvs_exchange_complete;
|
||||
jvs_exchange_error:
|
||||
log_error("mxjvs", "JVS status: 0x%02x", status);
|
||||
respIndex = 4; // As if we've just written status, but nothing else
|
||||
|
||||
jvs_exchange_complete:
|
||||
response[2] = (respIndex - 2) & 0xFF; // respIndex doesn't include SUM yet
|
||||
response[3] = status;
|
||||
|
||||
// Compute and set the checksum
|
||||
sum = 0;
|
||||
for (int i = 1; i < respIndex; i++) sum += response[i];
|
||||
response[respIndex++] = sum;
|
||||
|
||||
short paddedLength = jvs_pad(response, respIndex, outData, maxOut);
|
||||
// We failed hard. It's not worth sending an overflow response
|
||||
if (paddedLength == -1)
|
||||
*outCount = 0;
|
||||
else
|
||||
*outCount = 0x00000000 | paddedLength;
|
||||
|
||||
free(response);
|
||||
free(inData);
|
||||
}
|
||||
|
||||
BOOL mxjvs_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXJVS_EXCHANGE:
|
||||
log_trace("mxjvs",
|
||||
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize & 0xFFFF,
|
||||
(int*)lpBytesReturned);
|
||||
|
||||
break;
|
||||
default:
|
||||
log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxjvs_SetupComm(void* com, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
|
||||
BOOL mxjvs_PurgeComm(void* com, DWORD dwFlags) { return TRUE; }
|
||||
BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
|
||||
|
||||
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
|
||||
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
|
||||
char PARITY[] = { 'N', 'O', 'E', 'M', 'S' };
|
||||
char* STOP[] = { "1", "1.5", "2" };
|
||||
log_info("mxjvs", "Switching to %d baud (%d%c%s)", lpDCB->BaudRate, lpDCB->ByteSize,
|
||||
PARITY[lpDCB->Parity], STOP[lpDCB->StopBits]);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxjvs() {
|
||||
file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs");
|
||||
mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl;
|
||||
|
||||
com_hook_t* jvscom = new_com_hook(0);
|
||||
wcscpy_s(jvscom->wName, sizeof jvscom->wName, L"\\\\.\\mxjvs");
|
||||
wcscpy_s(jvscom->wDosName, sizeof jvscom->wDosName, L"\\\\.\\mxjvs");
|
||||
jvscom->GetCommState = mxjvs_GetCommState;
|
||||
jvscom->SetCommState = mxjvs_SetCommState;
|
||||
jvscom->SetCommTimeouts = mxjvs_SetCommTimeouts;
|
||||
jvscom->SetupComm = mxjvs_SetupComm;
|
||||
jvscom->PurgeComm = mxjvs_PurgeComm;
|
||||
jvscom->GetCommModemStatus = mxjvs_GetCommModemStatus;
|
||||
|
||||
hook_file(mxjvs);
|
||||
hook_com(jvscom);
|
||||
}
|
||||
|
@ -1,337 +1,365 @@
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "../hooks/setupapi_.h"
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
// PCA9535 (DIPSW)
|
||||
#define PCA9535_WRITE 0x04
|
||||
#define PCA9535_READ 0x05
|
||||
|
||||
#define PCA9535_IN0 0x00
|
||||
#define PCA9535_IN1 0x01
|
||||
#define PCA9535_OUT0 0x02
|
||||
#define PCA9535_OUT1 0x03
|
||||
#define PCA9535_INV0 0x04
|
||||
#define PCA9535_INV1 0x05
|
||||
#define PCA9535_CONF0 0x06
|
||||
#define PCA9535_CONF1 0x07
|
||||
|
||||
#define SMBUS_PCA9535 0x20
|
||||
#define SMBUS_EEPROM 0x57 // Doesn't line up with manual!
|
||||
|
||||
#define SMBUS_DDR2_DIMM_A1 0x000 // what does 0xA0 mean?
|
||||
#define SMBUS_DDR2_DIMM_B1 0x010 // what does 0xA4 mean?
|
||||
#define SMBUS_EEPROM_ 0x0AE // = AT24C64AN
|
||||
#define SMBUS_ICS9LPRS908 0xfff // Unknown
|
||||
#define SMBUS_W83627UHG 0xfff // Unknown; hwmon. Possibly 0x2e or 0x4e
|
||||
#define SMBUS_UPI_UP6261BM8 0xfff // Unknown; vref
|
||||
#define SMBUS_UPI_ISL6322CR 0xfff // Unknown; vrm
|
||||
// SMBUS is send onto the mezzanine board!
|
||||
|
||||
#define EEPROM_DUMP L"dev/eeprom.bin"
|
||||
typedef struct eeprom_reg {
|
||||
BYTE data[32];
|
||||
} eeprom_reg_t;
|
||||
typedef struct eeprom_bank {
|
||||
eeprom_reg_t reg[0x100];
|
||||
} eeprom_bank_t;
|
||||
|
||||
// 256 registers, 32 bytes each
|
||||
eeprom_bank_t EEPROM_DATA;
|
||||
/*
|
||||
* Known registers:
|
||||
* - Reg 0x00: Stores ??? in [00]
|
||||
* - Reg 0x08: Stores LPC address in [00, 01]
|
||||
* - Reg 0x16: Stores ??? in [00, 01]
|
||||
* - Reg 0x0e: Stores
|
||||
*/
|
||||
|
||||
void eeprom_dump() {
|
||||
HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) {
|
||||
log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed");
|
||||
return;
|
||||
}
|
||||
_WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL);
|
||||
FlushFileBuffers(dump);
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
void eeprom_restore() {
|
||||
HANDLE dump =
|
||||
_CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) return;
|
||||
DWORD read;
|
||||
if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL))
|
||||
log_error("eeprom", "failed to restore (%d)", GetLastError());
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
DWORD eeprom_crc(BYTE reg) {
|
||||
if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) {
|
||||
// Some registers are only treated as 16 byte values
|
||||
crc32_build_table();
|
||||
return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0);
|
||||
}
|
||||
|
||||
crc32_build_table();
|
||||
return crc32(28, EEPROM_DATA.reg[reg].data + 4, 0);
|
||||
}
|
||||
void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) {
|
||||
eeprom_restore();
|
||||
for (BYTE i = index; i < index + length; i++) {
|
||||
if (i > 0x1f) break;
|
||||
|
||||
BYTE byte = EEPROM_DATA.reg[reg].data[i];
|
||||
|
||||
// If register has a CRC
|
||||
// if (reg == 0x00 || reg == 0x01 || reg == 0x02 || reg == 0x10 || reg
|
||||
// == 0x11 || reg == 0x12 || reg == 0x200) {
|
||||
if (true) {
|
||||
// Intercept the read and inject a CRC instead
|
||||
if (i == 0x00 || i == 0x01 || i == 0x02 || i == 0x03) {
|
||||
DWORD crc = eeprom_crc(reg);
|
||||
byte = crc >> 8 * i & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
data[i - index] = byte;
|
||||
}
|
||||
}
|
||||
void eeprom_write(BYTE reg, BYTE index, BYTE* data, BYTE length) {
|
||||
for (BYTE i = index; i < index + length; i++) {
|
||||
if (i > 0x1f) break;
|
||||
EEPROM_DATA.reg[reg].data[i] = data[i - index];
|
||||
}
|
||||
eeprom_dump();
|
||||
}
|
||||
|
||||
BYTE eeprom_read_one(BYTE reg, BYTE index) {
|
||||
BYTE data;
|
||||
eeprom_read(reg, index, &data, 1);
|
||||
return data;
|
||||
}
|
||||
void eeprom_write_one(BYTE reg, BYTE index, BYTE data) { eeprom_write(reg, index, &data, 1); }
|
||||
|
||||
BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer;
|
||||
mxsmbus_i2c_packet* i2c_out = (mxsmbus_i2c_packet*)lpOutBuffer;
|
||||
|
||||
mxsmbus_request_packet* request_packet = (mxsmbus_request_packet*)lpInBuffer;
|
||||
mxsmbus_request_packet* request_out = (mxsmbus_request_packet*)lpOutBuffer;
|
||||
|
||||
BYTE dlen;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSMBUS_GET_VERSION:
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <get version>, 0x%p, 0x%x, "
|
||||
"-, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = 0x01020001;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSMBUS_REQUEST: // dip r/w
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <request>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
// Game trace:
|
||||
// 05 for 20
|
||||
// ^[x3]
|
||||
// 04 for 20
|
||||
// ^[x3]
|
||||
// 05 for 20
|
||||
// 03 for 57
|
||||
// ^[after every eeprom read/write]
|
||||
|
||||
// Address 0x20 = PCA9535 = DIP switches
|
||||
// Address 0x30 = Keychip? "N2"
|
||||
// Address 0x55 = Keychip?
|
||||
// Address 0x57 = EEPROM
|
||||
|
||||
// dyn = 0x57
|
||||
// 03: addr dyn: amEepromWait
|
||||
// 04: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
|
||||
// 05: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
|
||||
//
|
||||
// dyn2 = 0x20
|
||||
// 04: addr dyn2: amDipswWriteByteInternal
|
||||
// 05: addr dyn2: amDipswReadByteInternal[Ex]
|
||||
|
||||
// 0B: addr 0x20: amHmGetLPCChipId
|
||||
// 0B: addr 0x21: amHmGetLPCChipId
|
||||
// 48: addr 0x00: amHmGetLPCChipId
|
||||
|
||||
switch (i2c_packet->addr) {
|
||||
case SMBUS_PCA9535:
|
||||
switch (i2c_packet->prt) {
|
||||
case PCA9535_WRITE:
|
||||
switch (i2c_packet->reg) {
|
||||
case PCA9535_OUT1:
|
||||
log_info("mxsmbus", "pca9535 OUT1: %02x %02x", i2c_packet->data[0],
|
||||
i2c_packet->data[1]);
|
||||
break;
|
||||
case PCA9535_INV0:
|
||||
log_info("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0],
|
||||
i2c_packet->data[1]);
|
||||
break;
|
||||
case PCA9535_INV1:
|
||||
log_info("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0],
|
||||
i2c_packet->data[1]);
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux",
|
||||
"(write) Undefined pca9535 "
|
||||
"register: 0x%02x",
|
||||
i2c_packet->reg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case PCA9535_READ:
|
||||
switch (i2c_packet->reg) {
|
||||
case PCA9535_IN0: // DIPSW
|
||||
i2c_packet->data[0] = 0x00;
|
||||
break;
|
||||
case PCA9535_IN1: // SW1/2 + extras
|
||||
/*
|
||||
0: uk
|
||||
1: uk
|
||||
2: ¬test
|
||||
3: ¬service
|
||||
4: uk
|
||||
5: uk
|
||||
6: uk
|
||||
7: uk
|
||||
*/
|
||||
i2c_packet->data[0] = 0x0c;
|
||||
break;
|
||||
case PCA9535_INV0:
|
||||
case PCA9535_INV1:
|
||||
case PCA9535_OUT1: // LEDs, probably
|
||||
i2c_packet->data[0] = 0x00;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux",
|
||||
"(read) Undefined pca9535 "
|
||||
"register: 0x%02x",
|
||||
i2c_packet->reg);
|
||||
exit(1);
|
||||
}
|
||||
i2c_packet->status = 0x00;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux", "Unknown pca9535 command: 0x%02x", i2c_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case SMBUS_EEPROM:
|
||||
switch (i2c_packet->prt) {
|
||||
case 3: // Wait
|
||||
// 0x18 = wait, 0x00 = done
|
||||
i2c_packet->status = 0;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux", "Unknown eeprom command: 0x%02x", i2c_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus", "Unknown smbus device: 0x%02x", i2c_packet->addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i2c_out->status = MXSBUS_OKAY;
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_i2c_packet);
|
||||
break;
|
||||
case IOCTL_MXSMBUS_I2C: // i2c r/w
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <i2c>, 0x%p, 0x%x, -, 0x%x, "
|
||||
"-, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
log_misc("mxsmbus", "SMBus I2C request for %02x: 0x%02x (%02x bytes @ %02x)", request_packet->addr,
|
||||
request_packet->prt, request_packet->dlen, request_packet->reg);
|
||||
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[0],
|
||||
// dwordInBuffer[1], dwordInBuffer[2], dwordInBuffer[3]);
|
||||
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[4],
|
||||
// dwordInBuffer[5], dwordInBuffer[6], dwordInBuffer[7]);
|
||||
// log_warning("eeprom", "%08x %08x", dwordInBuffer[8],
|
||||
// dwordInBuffer[9]);
|
||||
|
||||
// for (int i = 0; i < nInBufferSize; i++) {
|
||||
// printf("%02x ", ((LPBYTE)lpInBuffer)[i]);
|
||||
// }
|
||||
// puts("");
|
||||
|
||||
// prt = byteInBuffer[1];
|
||||
// addr = wordInBuffer[1];
|
||||
// reg = wordInBuffer[2] & 0xFF;
|
||||
dlen = request_packet->dlen;
|
||||
if (dlen > 0x20) dlen = 0x20;
|
||||
|
||||
/*
|
||||
* Known addresses:
|
||||
* - 0x57: EEPROM
|
||||
**/
|
||||
|
||||
request_packet->status = MXSBUS_OKAY;
|
||||
|
||||
if (request_packet->status != 0) {
|
||||
log_error("mxsmbus", "invalid i2c packet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (request_packet->addr != SMBUS_EEPROM) {
|
||||
log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr);
|
||||
exit(1);
|
||||
}
|
||||
// 04 = Write byte
|
||||
// 05 = Read byte
|
||||
//
|
||||
// 08 = Write block
|
||||
// 09 = Read block
|
||||
|
||||
if (request_packet->prt == 0x08) {
|
||||
// Write
|
||||
log_misc("mxsmbus", "eeprom write %02x (0x%04x)", dlen, request_packet->reg);
|
||||
// for (int i = 0; i < dlen; i++) printf("%02x ",
|
||||
// request_packet->data[i]); puts("");
|
||||
|
||||
eeprom_write(request_packet->reg >> 5, request_packet->reg & 0x1f, request_packet->data,
|
||||
request_packet->dlen);
|
||||
request_out->status = 0;
|
||||
} else if (i2c_packet->prt == 0x09) {
|
||||
// Read
|
||||
log_misc("mxsmbus", "eeprom read %02x (0x%04x)", dlen, request_packet->reg);
|
||||
eeprom_read(request_packet->reg >> 5, request_packet->reg & 0x1f, request_out->data, dlen);
|
||||
// for (int i = 0; i < dlen; i++) printf("%02x ",
|
||||
// request_out->data[i]); puts("");
|
||||
request_out->status = 0;
|
||||
} else {
|
||||
log_warning("mxsmbus", "UNHANDLED MXSMBUS I2C %02x", request_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_request_packet);
|
||||
break;
|
||||
default:
|
||||
log_warning("mxsmbus", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsmbus() {
|
||||
file_hook_t* mxsmbus = new_file_hook(L"\\\\.\\mxsmbus");
|
||||
mxsmbus->DeviceIoControl = &mxsmbus_DeviceIoControl;
|
||||
|
||||
hook_file(mxsmbus);
|
||||
|
||||
if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) {
|
||||
log_error("mxsmbus", "failed to install mxsmbus device");
|
||||
}
|
||||
}
|
||||
#include "../hooks/setupapi_.h"
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
#define EEPROM_DUMP L"dev/eeprom.bin"
|
||||
typedef struct eeprom_reg {
|
||||
BYTE data[32];
|
||||
} eeprom_reg_t;
|
||||
typedef struct eeprom_bank {
|
||||
eeprom_reg_t reg[0x100];
|
||||
} eeprom_bank_t;
|
||||
|
||||
// 256 registers, 32 bytes each
|
||||
eeprom_bank_t EEPROM_DATA;
|
||||
/*
|
||||
* Known registers:
|
||||
* - Reg 0x00: Stores ??? in [00]
|
||||
* - Reg 0x08: Stores LPC address in [00, 01]
|
||||
* - Reg 0x16: Stores ??? in [00, 01]
|
||||
* - Reg 0x0e: Stores
|
||||
*/
|
||||
|
||||
void eeprom_dump() {
|
||||
HANDLE dump =
|
||||
_CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) {
|
||||
log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed");
|
||||
return;
|
||||
} else {
|
||||
log_info("eeprom", "Wrote eeprom to %s", EEPROM_DUMP);
|
||||
}
|
||||
_WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL);
|
||||
FlushFileBuffers(dump);
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
void eeprom_restore() {
|
||||
HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) {
|
||||
// Make the file, even though it'll probably be empty
|
||||
eeprom_dump();
|
||||
return;
|
||||
}
|
||||
DWORD read;
|
||||
if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL))
|
||||
log_error("eeprom", "failed to restore (%d)", GetLastError());
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
DWORD eeprom_crc(BYTE reg) {
|
||||
if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) {
|
||||
// Some registers are only treated as 16 byte values
|
||||
crc32_build_table();
|
||||
return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0);
|
||||
}
|
||||
|
||||
crc32_build_table();
|
||||
return crc32(28, EEPROM_DATA.reg[reg].data + 4, 0);
|
||||
}
|
||||
void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) {
|
||||
log_game("eeprom", "EEPROM READ %d %d %d", reg, index, length);
|
||||
|
||||
eeprom_restore();
|
||||
for (BYTE i = index; i < index + length; i++) {
|
||||
if (i > 0x1f) break;
|
||||
|
||||
BYTE byte = EEPROM_DATA.reg[reg].data[i];
|
||||
|
||||
// TODO: Reg 1 and 17 in the EEPROM are system info. We should fake these!
|
||||
|
||||
// If register has a CRC
|
||||
// if (reg == 0x00 || reg == 0x01 || reg == 0x02 || reg == 0x10 || reg
|
||||
// == 0x11 || reg == 0x12 || reg == 0x200) {
|
||||
if (false) {
|
||||
// Intercept the read and inject a CRC instead
|
||||
if (i == 0x00 || i == 0x01 || i == 0x02 || i == 0x03) {
|
||||
DWORD crc = eeprom_crc(reg);
|
||||
byte = crc >> 8 * i & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
data[i - index] = byte;
|
||||
}
|
||||
}
|
||||
void eeprom_write(BYTE reg, BYTE index, BYTE* data, BYTE length) {
|
||||
log_game("eeprom", "EEPROM WRITE %d %d %d", reg, index, length);
|
||||
|
||||
for (BYTE i = index; i < index + length; i++) {
|
||||
if (i > 0x1f) break;
|
||||
EEPROM_DATA.reg[reg].data[i] = data[i - index];
|
||||
}
|
||||
eeprom_dump();
|
||||
}
|
||||
|
||||
BYTE eeprom_read_one(BYTE reg, BYTE index) {
|
||||
BYTE data;
|
||||
eeprom_read(reg, index, &data, 1);
|
||||
return data;
|
||||
}
|
||||
void eeprom_write_one(BYTE reg, BYTE index, BYTE data) { eeprom_write(reg, index, &data, 1); }
|
||||
|
||||
BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer;
|
||||
mxsmbus_i2c_packet* i2c_out = (mxsmbus_i2c_packet*)lpOutBuffer;
|
||||
|
||||
mxsmbus_request_packet* request_packet = (mxsmbus_request_packet*)lpInBuffer;
|
||||
mxsmbus_request_packet* request_out = (mxsmbus_request_packet*)lpOutBuffer;
|
||||
|
||||
BYTE dlen;
|
||||
|
||||
static uint16_t pca9535_config = 0xffff;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSMBUS_GET_VERSION:
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <get version>, 0x%p, 0x%x, "
|
||||
"-, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = 0x01020001;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSMBUS_REQUEST: // dip r/w
|
||||
log_trace("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <request>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
// Game trace:
|
||||
// 05 for 20
|
||||
// ^[x3]
|
||||
// 04 for 20
|
||||
// ^[x3]
|
||||
// 05 for 20
|
||||
// 03 for 57
|
||||
// ^[after every eeprom read/write]
|
||||
|
||||
// Address 0x20 = PCA9535 = DIP switches
|
||||
// Address 0x30 = Keychip? "N2"
|
||||
// Address 0x55 = Keychip?
|
||||
// Address 0x57 = EEPROM
|
||||
|
||||
// dyn = 0x57
|
||||
// 03: addr dyn: amEepromWait
|
||||
// 04: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
|
||||
// 05: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
|
||||
//
|
||||
// dyn2 = 0x20
|
||||
// 04: addr dyn2: amDipswWriteByteInternal
|
||||
// 05: addr dyn2: amDipswReadByteInternal[Ex]
|
||||
|
||||
// 0B: addr 0x20: amHmGetLPCChipId
|
||||
// 0B: addr 0x21: amHmGetLPCChipId
|
||||
// 48: addr 0x00: amHmGetLPCChipId
|
||||
|
||||
switch (i2c_packet->addr) {
|
||||
case SMBUS_PCA9535:
|
||||
switch (i2c_packet->prt) {
|
||||
case PCA9535_WRITE:
|
||||
switch (i2c_packet->reg) {
|
||||
case PCA9535_OUT0:
|
||||
log_info("mxsmbus", "pca9535 OUT0: %02x", i2c_packet->data[0]);
|
||||
break;
|
||||
case PCA9535_OUT1:
|
||||
log_info("mxsmbus", "pca9535 OUT1: %02x", i2c_packet->data[0]);
|
||||
break;
|
||||
case PCA9535_INV0:
|
||||
log_info("mxsmbus", "pca9535 INV0: %02x", i2c_packet->data[0]);
|
||||
break;
|
||||
case PCA9535_INV1:
|
||||
log_info("mxsmbus", "pca9535 INV1: %02x", i2c_packet->data[0]);
|
||||
break;
|
||||
case PCA9535_CONF0:
|
||||
log_info("mxsmbus", "pca9535 CONF0: %02x", i2c_packet->data[0]);
|
||||
pca9535_config =
|
||||
(i2c_packet->data[0] << 8) | (pca9535_config & 0xff);
|
||||
break;
|
||||
case PCA9535_CONF1:
|
||||
log_info("mxsmbus", "pca9535 CONF1: %02x", i2c_packet->data[0]);
|
||||
pca9535_config =
|
||||
i2c_packet->data[0] | (pca9535_config & 0xff00);
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus",
|
||||
"(write) Undefined pca9535 register: 0x%02x",
|
||||
i2c_packet->reg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case PCA9535_READ:
|
||||
switch (i2c_packet->reg) {
|
||||
case PCA9535_IN0: // DIPSW
|
||||
/*
|
||||
0: ?
|
||||
1: ?
|
||||
2: ?
|
||||
3: Orientation
|
||||
4: / \
|
||||
5: | Resolution |
|
||||
6: \ /
|
||||
7: game specific
|
||||
|
||||
0b00001000 = landscape
|
||||
*/
|
||||
puts("dipsw");
|
||||
i2c_packet->data[0] = 0b00001000;
|
||||
break;
|
||||
case PCA9535_IN1: // SW1/2 + extras
|
||||
/*
|
||||
0: unk
|
||||
1: unk
|
||||
2: ¬test
|
||||
3: ¬service
|
||||
4: unk
|
||||
5: unk
|
||||
6: unk
|
||||
7: unk
|
||||
*/
|
||||
byte dip = 0x00;
|
||||
if (GetAsyncKeyState('T') >= 0) {
|
||||
dip |= 0x04;
|
||||
}
|
||||
if (GetAsyncKeyState('S') >= 0) {
|
||||
dip |= 0x08;
|
||||
}
|
||||
i2c_packet->data[0] = dip;
|
||||
break;
|
||||
case PCA9535_INV0:
|
||||
case PCA9535_INV1:
|
||||
case PCA9535_OUT1: // LEDs, probably
|
||||
i2c_packet->data[0] = 0x00;
|
||||
break;
|
||||
case PCA9535_CONF0:
|
||||
i2c_packet->data[0] = pca9535_config >> 8;
|
||||
break;
|
||||
case PCA9535_CONF1:
|
||||
i2c_packet->data[0] = pca9535_config & 0xff;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus",
|
||||
"(read) Undefined pca9535 "
|
||||
"register: 0x%02x",
|
||||
i2c_packet->reg);
|
||||
exit(1);
|
||||
}
|
||||
i2c_packet->status = 0x00;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus", "Unknown pca9535 command: 0x%02x",
|
||||
i2c_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case SMBUS_EEPROM:
|
||||
switch (i2c_packet->prt) {
|
||||
case 3: // Wait
|
||||
// 0x18 = wait, 0x00 = done
|
||||
i2c_packet->status = 0;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus", "Unknown eeprom command: 0x%02x", i2c_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus", "Unknown smbus device: 0x%02x", i2c_packet->addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i2c_out->status = MXSBUS_OKAY;
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_i2c_packet);
|
||||
break;
|
||||
case IOCTL_MXSMBUS_I2C: // i2c r/w
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <i2c>, 0x%p, 0x%x, -, 0x%x, "
|
||||
"-, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
log_misc("mxsmbus", "SMBus I2C request for %02x: 0x%02x (%02x bytes @ %02x)",
|
||||
request_packet->addr, request_packet->prt, request_packet->dlen,
|
||||
request_packet->reg);
|
||||
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[0],
|
||||
// dwordInBuffer[1], dwordInBuffer[2], dwordInBuffer[3]);
|
||||
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[4],
|
||||
// dwordInBuffer[5], dwordInBuffer[6], dwordInBuffer[7]);
|
||||
// log_warning("eeprom", "%08x %08x", dwordInBuffer[8],
|
||||
// dwordInBuffer[9]);
|
||||
|
||||
// for (int i = 0; i < nInBufferSize; i++) {
|
||||
// printf("%02x ", ((LPBYTE)lpInBuffer)[i]);
|
||||
// }
|
||||
// puts("");
|
||||
|
||||
// prt = byteInBuffer[1];
|
||||
// addr = wordInBuffer[1];
|
||||
// reg = wordInBuffer[2] & 0xFF;
|
||||
dlen = request_packet->dlen;
|
||||
if (dlen > 0x20) dlen = 0x20;
|
||||
|
||||
/*
|
||||
* Known addresses:
|
||||
* - 0x57: EEPROM
|
||||
**/
|
||||
|
||||
request_packet->status = MXSBUS_OKAY;
|
||||
|
||||
if (request_packet->status != 0) {
|
||||
log_error("mxsmbus", "invalid i2c packet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (request_packet->addr != SMBUS_EEPROM) {
|
||||
log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr);
|
||||
exit(1);
|
||||
}
|
||||
// 04 = Write byte
|
||||
// 05 = Read byte
|
||||
//
|
||||
// 08 = Write block
|
||||
// 09 = Read block
|
||||
|
||||
if (request_packet->prt == 0x08) {
|
||||
// Write
|
||||
log_misc("mxsmbus", "eeprom write %02x (0x%04x)", dlen, request_packet->reg);
|
||||
// for (int i = 0; i < dlen; i++) printf("%02x ",
|
||||
// request_packet->data[i]); puts("");
|
||||
|
||||
eeprom_write((request_packet->reg >> 5) & 0xff, request_packet->reg & 0x1f,
|
||||
request_packet->data, request_packet->dlen);
|
||||
request_out->status = 0;
|
||||
} else if (i2c_packet->prt == 0x09) {
|
||||
// Read
|
||||
log_misc("mxsmbus", "eeprom read %02x (0x%04x)", dlen, request_packet->reg);
|
||||
eeprom_read((request_packet->reg >> 5) & 0xff, request_packet->reg & 0x1f,
|
||||
request_out->data, dlen);
|
||||
// for (int i = 0; i < dlen; i++) printf("%02x ",
|
||||
// request_out->data[i]); puts("");
|
||||
request_out->status = 0;
|
||||
} else {
|
||||
log_warning("mxsmbus", "UNHANDLED MXSMBUS I2C %02x", request_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_request_packet);
|
||||
break;
|
||||
default:
|
||||
log_warning("mxsmbus", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsmbus() {
|
||||
file_hook_t* mxsmbus = new_file_hook(L"\\\\.\\mxsmbus");
|
||||
mxsmbus->DeviceIoControl = &mxsmbus_DeviceIoControl;
|
||||
|
||||
hook_file(mxsmbus);
|
||||
|
||||
if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) {
|
||||
log_error("mxsmbus", "failed to install mxsmbus device");
|
||||
}
|
||||
}
|
||||
|
@ -1,125 +1,126 @@
|
||||
#include "mx.h"
|
||||
|
||||
#define SRAM_DUMP L"dev/sram.bin"
|
||||
#define SRAM_SIZE 1024 * 2084
|
||||
LPBYTE SRAM;
|
||||
DWORD SRAM_POINTER = 0;
|
||||
|
||||
void sram_dump() {
|
||||
HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) {
|
||||
log_error("sram", "CreateFileA(SRAM_DUMP) failed");
|
||||
return;
|
||||
}
|
||||
_WriteFile(dump, SRAM, SRAM_SIZE, NULL, NULL);
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
void sram_restore() {
|
||||
HANDLE dump =
|
||||
_CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) return;
|
||||
DWORD read;
|
||||
if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) log_error("sram", "failed to restore (%d)", GetLastError());
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
DWORD SRAM_VERSION = 0x0001;
|
||||
DWORD SRAM_SECTOR_SIZE = 0x100; // Max is 0x800
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSRAM_PING: // Get version
|
||||
log_info("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <ping>, 0x%p, 0x%x, -, 0x%x, "
|
||||
"-, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = SRAM_VERSION;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
|
||||
log_info("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <get drive geom>, 0x%p, "
|
||||
"0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
DISK_GEOMETRY out = *(PDISK_GEOMETRY)lpOutBuffer;
|
||||
memset(&out, 0, sizeof(out));
|
||||
out.Cylinders.QuadPart = 1;
|
||||
out.MediaType = FixedMedia;
|
||||
out.TracksPerCylinder = 224;
|
||||
out.SectorsPerTrack = 32;
|
||||
out.BytesPerSector = 1;
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY);
|
||||
break;
|
||||
case IOCTL_MXSRAM_GET_SECTOR_SIZE:
|
||||
log_info("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <get sector size>, 0x%p, "
|
||||
"0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = SRAM_SECTOR_SIZE;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
default:
|
||||
log_warning("mxsram", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
|
||||
if (dwMoveMethod == FILE_BEGIN) {
|
||||
SRAM_POINTER = lDistanceToMove;
|
||||
} else if (dwMoveMethod == FILE_CURRENT) {
|
||||
SRAM_POINTER += lDistanceToMove;
|
||||
}
|
||||
return SRAM_POINTER;
|
||||
}
|
||||
|
||||
BOOL mxsram_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
log_misc("mxsram", "sram write 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToWrite);
|
||||
if (SRAM_POINTER + nNumberOfBytesToWrite >= SRAM_SIZE) {
|
||||
nNumberOfBytesToWrite = SRAM_SIZE - SRAM_POINTER;
|
||||
}
|
||||
memcpy(SRAM + SRAM_POINTER, lpBuffer, nNumberOfBytesToWrite);
|
||||
sram_dump();
|
||||
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxsram_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
log_misc("mxsram", "sram read 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToRead);
|
||||
if (SRAM_POINTER + nNumberOfBytesToRead >= SRAM_SIZE) {
|
||||
nNumberOfBytesToRead = SRAM_SIZE - SRAM_POINTER;
|
||||
}
|
||||
sram_restore();
|
||||
memcpy((LPVOID)lpBuffer, SRAM + SRAM_POINTER, nNumberOfBytesToRead);
|
||||
*lpNumberOfBytesRead = nNumberOfBytesToRead;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsram() {
|
||||
// Allocate 2MB of SRAM
|
||||
SRAM = (LPBYTE)malloc(SRAM_SIZE);
|
||||
if (!SRAM) {
|
||||
log_error(BOOT_LOGGER, "unable to allocate 2MiB for SRAM");
|
||||
exit(1);
|
||||
}
|
||||
memset(SRAM, 0, SRAM_SIZE);
|
||||
sram_restore();
|
||||
|
||||
file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram");
|
||||
mxsram->DeviceIoControl = &mxsram_DeviceIoControl;
|
||||
mxsram->SetFilePointer = &mxsram_SetFilePointer;
|
||||
mxsram->ReadFile = &mxsram_ReadFile;
|
||||
mxsram->WriteFile = &mxsram_WriteFile;
|
||||
|
||||
hook_file(mxsram);
|
||||
}
|
||||
#include "mx.h"
|
||||
|
||||
#define SRAM_DUMP L"dev/sram.bin"
|
||||
#define SRAM_SIZE 1024 * 2084
|
||||
LPBYTE SRAM;
|
||||
DWORD SRAM_POINTER = 0;
|
||||
|
||||
void sram_dump() {
|
||||
HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) {
|
||||
log_error("sram", "CreateFileA(SRAM_DUMP) failed");
|
||||
return;
|
||||
}
|
||||
_WriteFile(dump, SRAM, SRAM_SIZE, NULL, NULL);
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
void sram_restore() {
|
||||
HANDLE dump =
|
||||
_CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) return;
|
||||
DWORD read;
|
||||
if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) log_error("sram", "failed to restore (%d)", GetLastError());
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
DWORD SRAM_VERSION = 0x0001;
|
||||
DWORD SRAM_SECTOR_SIZE = 4; // Max is 0x800
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSRAM_PING: // Get version
|
||||
log_info("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <ping>, 0x%p, 0x%x, -, 0x%x, "
|
||||
"-, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = SRAM_VERSION;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
|
||||
log_info("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <get drive geom>, 0x%p, "
|
||||
"0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
DISK_GEOMETRY out = *(PDISK_GEOMETRY)lpOutBuffer;
|
||||
memset(&out, 0, sizeof(out));
|
||||
out.Cylinders.QuadPart = 256;
|
||||
out.MediaType = FixedMedia;
|
||||
out.TracksPerCylinder = 24;
|
||||
out.SectorsPerTrack = 8;
|
||||
out.BytesPerSector = 512;
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY);
|
||||
break;
|
||||
case IOCTL_MXSRAM_GET_SECTOR_SIZE:
|
||||
log_info("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <get sector size>, 0x%p, "
|
||||
"0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = SRAM_SECTOR_SIZE;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
default:
|
||||
log_warning("mxsram", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
|
||||
printf("MXSRSFP %08x\n", lDistanceToMove);
|
||||
if (dwMoveMethod == FILE_BEGIN) {
|
||||
SRAM_POINTER = lDistanceToMove;
|
||||
} else if (dwMoveMethod == FILE_CURRENT) {
|
||||
SRAM_POINTER += lDistanceToMove;
|
||||
}
|
||||
return SRAM_POINTER;
|
||||
}
|
||||
|
||||
BOOL mxsram_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
log_misc("mxsram", "sram write 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToWrite);
|
||||
if (SRAM_POINTER + nNumberOfBytesToWrite >= SRAM_SIZE) {
|
||||
nNumberOfBytesToWrite = SRAM_SIZE - SRAM_POINTER;
|
||||
}
|
||||
memcpy(SRAM + SRAM_POINTER, lpBuffer, nNumberOfBytesToWrite);
|
||||
sram_dump();
|
||||
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxsram_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
log_misc("mxsram", "sram read 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToRead);
|
||||
if (SRAM_POINTER + nNumberOfBytesToRead >= SRAM_SIZE) {
|
||||
nNumberOfBytesToRead = SRAM_SIZE - SRAM_POINTER;
|
||||
}
|
||||
sram_restore();
|
||||
memcpy((LPVOID)lpBuffer, SRAM + SRAM_POINTER, nNumberOfBytesToRead);
|
||||
*lpNumberOfBytesRead = nNumberOfBytesToRead;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsram() {
|
||||
// Allocate 2MB of SRAM
|
||||
SRAM = (LPBYTE)malloc(SRAM_SIZE);
|
||||
if (!SRAM) {
|
||||
log_error(BOOT_LOGGER, "unable to allocate 2MiB for SRAM");
|
||||
exit(1);
|
||||
}
|
||||
memset(SRAM, 0, SRAM_SIZE);
|
||||
sram_restore();
|
||||
|
||||
file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram");
|
||||
mxsram->DeviceIoControl = &mxsram_DeviceIoControl;
|
||||
mxsram->SetFilePointer = &mxsram_SetFilePointer;
|
||||
mxsram->ReadFile = &mxsram_ReadFile;
|
||||
mxsram->WriteFile = &mxsram_WriteFile;
|
||||
|
||||
hook_file(mxsram);
|
||||
}
|
||||
|
@ -1,287 +1,395 @@
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
#include "w83791d.h"
|
||||
|
||||
BYTE w83791d_bank = 0x00;
|
||||
BYTE w83791d_config = W83791D_CONFIG_START;
|
||||
BYTE w83791d_noncrit_t1 = 75; // C
|
||||
BYTE w83791d_crit_t1 = 80; // C
|
||||
BYTE w83791d_noncrit_t2 = 75; // C
|
||||
BYTE w83791d_crit_t2 = 80; // C
|
||||
BYTE w83791d_noncrit_t3 = 75; // C
|
||||
BYTE w83791d_crit_t3 = 80; // C
|
||||
BYTE w83791d_vbat_monitor_control = 0x00;
|
||||
BOOL w83791d_4f_high = 0;
|
||||
|
||||
BOOL mxsuperio_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
mxsuperio_lpc_packet* lpc_packet = (mxsuperio_lpc_packet*)lpInBuffer;
|
||||
mxsuperio_lpc_packet* lpc_out = (mxsuperio_lpc_packet*)lpOutBuffer;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSUPERIO_PING:
|
||||
log_misc("mxsuperio",
|
||||
"DeviceIoControl(<mxsuperio>, <ping>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = 0x01000001;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSUPERIO_READ:
|
||||
log_misc("mxsuperio",
|
||||
"DeviceIoControl(<mxsuperio>, <read>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
/*
|
||||
BYTE chipId = 0|1
|
||||
BYTE ?? = 0x0b
|
||||
BYTE ?? = 0x20|0x21
|
||||
BYTE ret = 0
|
||||
*/
|
||||
|
||||
switch (((LPBYTE)lpInBuffer)[2]) {
|
||||
case 0x20:
|
||||
((LPBYTE)lpInBuffer)[3] = 0xa0;
|
||||
break;
|
||||
case 0x21:
|
||||
((LPBYTE)lpInBuffer)[3] = 0x20;
|
||||
break;
|
||||
default:
|
||||
((LPBYTE)lpInBuffer)[3] = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSUPERIO_HWMONITOR_LPC_READ: {
|
||||
BYTE index = lpc_packet->index;
|
||||
BYTE reg = lpc_packet->reg;
|
||||
|
||||
switch (w83791d_bank) {
|
||||
case 0x00: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_WCHIPID:
|
||||
lpc_out->data = 0x71;
|
||||
break;
|
||||
case W83791D_REG_CHIPMAN:
|
||||
if (w83791d_4f_high)
|
||||
lpc_out->data = 0x5c; // High byte
|
||||
else
|
||||
lpc_out->data = 0xa3; // Low byte
|
||||
break;
|
||||
case W83791D_REG_I2C_ADDR:
|
||||
lpc_out->data = 0x11;
|
||||
break;
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
case W83791D_REG_CONFIG:
|
||||
lpc_out->data = w83791d_config;
|
||||
break;
|
||||
|
||||
case W83791D_REG_BEEP_CTRL_0:
|
||||
lpc_out->data = 0xff; // All the beeps! (see main.h)
|
||||
break;
|
||||
|
||||
case W83791D_REG_TEMP1_0:
|
||||
lpc_out->data = 0x00; // TODO: Figure out the temp val lol
|
||||
break;
|
||||
case W83791D_RAM_VCOREA:
|
||||
case W83791D_RAM_VNIR0:
|
||||
case W83791D_RAM_12VIN:
|
||||
lpc_out->data = 0x00; // TODO: Figure out the batt val
|
||||
break;
|
||||
|
||||
case W83791D_RAM_FAN1:
|
||||
case W83791D_RAM_FAN2:
|
||||
case W83791D_RAM_FAN3:
|
||||
lpc_out->data = 0x00; // Fan no spinny!
|
||||
break;
|
||||
|
||||
case W83791D_VID_FAN_DIV:
|
||||
// Boths fans divide by 2 (01), VDD 5 latched
|
||||
// good.
|
||||
lpc_out->data = 0b01011111; // Let's not /0!
|
||||
break;
|
||||
|
||||
case W83791D_VBAT_MONITOR_CONTROL:
|
||||
lpc_out->data = w83791d_vbat_monitor_control;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b0 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x01: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
case W83791D_NONCRIT_TEMP_1:
|
||||
lpc_out->data = w83791d_noncrit_t1;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_1:
|
||||
lpc_out->data = w83791d_crit_t1;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_2:
|
||||
lpc_out->data = w83791d_noncrit_t2;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_2:
|
||||
lpc_out->data = w83791d_crit_t2;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_3:
|
||||
lpc_out->data = w83791d_noncrit_t3;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_3:
|
||||
lpc_out->data = w83791d_crit_t3;
|
||||
break;
|
||||
|
||||
case W83791D_VIN0:
|
||||
lpc_out->data = W83791D_ENTITY_CPU;
|
||||
break;
|
||||
case W83791D_VIN1:
|
||||
lpc_out->data = W83791D_ENTITY_SYSTEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x05: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
// Used in amHmReadVoltageInternal
|
||||
// What are these??
|
||||
case 0x51:
|
||||
case 0x40:
|
||||
lpc_out->data = 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// reg 0x48 = LPC Chip ID
|
||||
// index = 0,1
|
||||
// data > 0x0f, data < 0x70
|
||||
|
||||
// lpc_out->data = eeprom_read_one(reg, index);
|
||||
log_misc("mxsuperio", "amHmLpcReadByte Index=0x%02x Reg=0x%02x Data=0x%02x", index, reg, lpc_out->data);
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsuperio_lpc_packet);
|
||||
} break;
|
||||
case IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE: {
|
||||
BYTE index = lpc_packet->index;
|
||||
BYTE reg = lpc_packet->reg;
|
||||
log_misc("mxsuperio", "amHmLpcWriteByte Index=0x%02x Reg=0x%02x Data=0x%02b", index, reg, lpc_packet->data);
|
||||
|
||||
switch (w83791d_bank) {
|
||||
case 0x00: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BEEP_CTRL_0:
|
||||
// Ignore for now
|
||||
break;
|
||||
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
case W83791D_REG_CONFIG:
|
||||
w83791d_config = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_VBAT_MONITOR_CONTROL:
|
||||
w83791d_vbat_monitor_control = lpc_packet->data;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b0 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
|
||||
case W83791D_NONCRIT_TEMP_1:
|
||||
w83791d_noncrit_t1 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_1:
|
||||
w83791d_crit_t1 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_2:
|
||||
w83791d_noncrit_t2 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_2:
|
||||
w83791d_crit_t2 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_3:
|
||||
w83791d_noncrit_t3 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_3:
|
||||
w83791d_crit_t3 = lpc_packet->data;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x05: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
|
||||
// Used in amHmReadVoltageInternal
|
||||
// What is this??
|
||||
case 0x40:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 0;
|
||||
} break;
|
||||
default:
|
||||
log_warning("mxsuperio", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsuperio() {
|
||||
file_hook_t* mxsuperio = new_file_hook(L"\\\\.\\mxsuperio");
|
||||
mxsuperio->DeviceIoControl = &mxsuperio_DeviceIoControl;
|
||||
|
||||
hook_file(mxsuperio);
|
||||
}
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
#include "w83791d.h"
|
||||
#include "w83627uhg.h"
|
||||
|
||||
BYTE w83791d_bank = 0x00;
|
||||
BYTE w83791d_config = W83791D_CONFIG_START;
|
||||
BYTE w83791d_noncrit_t1 = 75; // C
|
||||
BYTE w83791d_crit_t1 = 80; // C
|
||||
BYTE w83791d_noncrit_t2 = 75; // C
|
||||
BYTE w83791d_crit_t2 = 80; // C
|
||||
BYTE w83791d_noncrit_t3 = 75; // C
|
||||
BYTE w83791d_crit_t3 = 80; // C
|
||||
BYTE w83791d_vbat_monitor_control = 0x00;
|
||||
BOOL w83791d_4f_high = 0;
|
||||
|
||||
BYTE w83627uhg_fanconf = 0x01;
|
||||
BYTE w83627uhg_fanconf_2 = 0x00;
|
||||
BYTE w83627uhg_cpufanout_src_slct = 0x2d;
|
||||
BYTE w83627uhg_sysfanout_src_slct = 0x00;
|
||||
BYTE w83627uhg_systin_target = 0x00;
|
||||
BYTE w83627uhg_cputin_target = 0x00;
|
||||
BYTE w83627uhg_target_tolerance = 0x00;
|
||||
|
||||
BOOL mxsuperio_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
mxsuperio_lpc_packet* lpc_packet = (mxsuperio_lpc_packet*)lpInBuffer;
|
||||
mxsuperio_lpc_packet* lpc_out = (mxsuperio_lpc_packet*)lpOutBuffer;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSUPERIO_PING:
|
||||
log_misc("mxsuperio",
|
||||
"DeviceIoControl(<mxsuperio>, <ping>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = 0x01000001;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSUPERIO_READ: {
|
||||
BYTE chip = ((LPBYTE)lpInBuffer)[0];
|
||||
BYTE device = ((LPBYTE)lpInBuffer)[1];
|
||||
BYTE index = ((LPBYTE)lpInBuffer)[2];
|
||||
BYTE* data = &((LPBYTE)lpInBuffer)[3];
|
||||
|
||||
log_misc("mxsuperio", "read: chip:%d device:%d index:%02x", chip, device, index);
|
||||
|
||||
/*
|
||||
{
|
||||
IN BYTE chip select (0 = base 0x2e, 1 = base 0x4e)
|
||||
IN BYTE logical device (0 = FDC, 11 = HW mon)
|
||||
IN BYTE index
|
||||
OUT BYTE read value
|
||||
}
|
||||
|
||||
The 846-5004D I have here is at base address 0x4e
|
||||
*/
|
||||
|
||||
/*
|
||||
from micedump:
|
||||
0.20: 00 0b 20 ff
|
||||
0.21: 00 0b 21 ff
|
||||
1.20: 01 0b 20 a2
|
||||
1.21: 01 0b 21 32
|
||||
*/
|
||||
|
||||
*data = 0xff;
|
||||
if (chip == 1) {
|
||||
if (device == 11) {
|
||||
switch (index) {
|
||||
case 0x20:
|
||||
*data = 0xa2;
|
||||
break;
|
||||
case 0x21:
|
||||
*data = 0x32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
}
|
||||
case IOCTL_MXSUPERIO_WRITE:
|
||||
log_misc("mxsuperio",
|
||||
"DeviceIoControl(<mxsuperio>, <write>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
/*
|
||||
{
|
||||
IN BYTE chip select (0 = base 0x2e, 1 = base 0x4e)
|
||||
IN BYTE logical device (0 = FPC, 11 = HW mon)
|
||||
IN BYTE index
|
||||
IN BYTE write value
|
||||
}
|
||||
*/
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSUPERIO_HWMONITOR_LPC_READ: {
|
||||
// TODO: This code is all for W83791D, however W83627UHG is more appropriate in some
|
||||
// cases. Is this an AAL vs AAM difference? Where was the W83791D usage derived from?
|
||||
BYTE index = lpc_packet->index;
|
||||
BYTE reg = lpc_packet->reg;
|
||||
|
||||
switch (w83791d_bank) {
|
||||
case 0x00: {
|
||||
switch (reg) {
|
||||
case W83627UHG_REG_FAN_CONF:
|
||||
lpc_out->data = w83627uhg_fanconf;
|
||||
break;
|
||||
case W83627UHG_REG_FAN_CONF_2:
|
||||
lpc_out->data = w83627uhg_fanconf_2;
|
||||
break;
|
||||
case W83627UHG_REG_CPUFANOUT_TEMP_SRC_SLCT:
|
||||
lpc_out->data = w83627uhg_cpufanout_src_slct;
|
||||
break;
|
||||
case W83627UHG_REG_SYSFANOUT_TEMP_SRC_SLCT:
|
||||
lpc_out->data = w83627uhg_sysfanout_src_slct;
|
||||
break;
|
||||
case W83627UHG_REG_SYSTIN_TARGET_TEMP:
|
||||
lpc_out->data = w83627uhg_systin_target;
|
||||
break;
|
||||
case W83627UHG_REG_CPUTIN_TARGET_TEMP:
|
||||
lpc_out->data = w83627uhg_cputin_target;
|
||||
break;
|
||||
case W83627UHG_REG_TARGET_TEMP_TOLERANCE:
|
||||
lpc_out->data = w83627uhg_target_tolerance;
|
||||
break;
|
||||
|
||||
case W83791D_REG_WCHIPID:
|
||||
lpc_out->data = 0x71; // Observed: c1
|
||||
break;
|
||||
case W83791D_REG_CHIPMAN:
|
||||
if (w83791d_4f_high)
|
||||
lpc_out->data = 0x5c; // High byte
|
||||
else
|
||||
lpc_out->data = 0xa3; // Low byte
|
||||
break;
|
||||
case W83791D_REG_I2C_ADDR:
|
||||
lpc_out->data = 0x11; // Observed: 2d
|
||||
break;
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
case W83791D_REG_CONFIG:
|
||||
lpc_out->data = w83791d_config;
|
||||
break;
|
||||
|
||||
case W83791D_REG_BEEP_CTRL_0:
|
||||
// No beeping :(
|
||||
lpc_out->data = 0x00;
|
||||
break;
|
||||
|
||||
// TODO: No idea how to read any of these. Pulled from real system
|
||||
case W83791D_REG_TEMP1_0:
|
||||
lpc_out->data = 0x1a;
|
||||
break;
|
||||
case W83791D_RAM_VCOREA:
|
||||
lpc_out->data = 0x76;
|
||||
break;
|
||||
case W83791D_RAM_VNIR0:
|
||||
lpc_out->data = 0x86;
|
||||
break;
|
||||
case W83791D_RAM_VDD5:
|
||||
lpc_out->data = 0x94;
|
||||
break;
|
||||
case W83791D_RAM_12VIN:
|
||||
lpc_out->data = 0xbe;
|
||||
break;
|
||||
case W83791D_RAM_N12VIN:
|
||||
lpc_out->data = 0xd1;
|
||||
break;
|
||||
|
||||
case W83791D_RAM_FAN1:
|
||||
case W83791D_RAM_FAN2:
|
||||
case W83791D_RAM_FAN3:
|
||||
lpc_out->data = 0x00; // Fan no spinny!
|
||||
break;
|
||||
|
||||
case W83791D_VID_FAN_DIV:
|
||||
// Boths fans divide by 2 (01)
|
||||
lpc_out->data = 0b00000101;
|
||||
break;
|
||||
|
||||
case W83791D_VBAT_MONITOR_CONTROL:
|
||||
lpc_out->data = w83791d_vbat_monitor_control;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b0 register: read 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x01: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
case W83791D_NONCRIT_TEMP_1:
|
||||
lpc_out->data = w83791d_noncrit_t1;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_1:
|
||||
lpc_out->data = w83791d_crit_t1;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_2:
|
||||
lpc_out->data = w83791d_noncrit_t2;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_2:
|
||||
lpc_out->data = w83791d_crit_t2;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_3:
|
||||
lpc_out->data = w83791d_noncrit_t3;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_3:
|
||||
lpc_out->data = w83791d_crit_t3;
|
||||
break;
|
||||
|
||||
case W83791D_VIN0:
|
||||
lpc_out->data = W83791D_ENTITY_CPU;
|
||||
break;
|
||||
case W83791D_VIN1:
|
||||
lpc_out->data = W83791D_ENTITY_SYSTEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x05: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
// Used in amHmReadVoltageInternal
|
||||
// What are these??
|
||||
case 0x51:
|
||||
case 0x40:
|
||||
lpc_out->data = 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// reg 0x48 = LPC Chip ID
|
||||
// index = 0,1
|
||||
// data > 0x0f, data < 0x70
|
||||
|
||||
// lpc_out->data = eeprom_read_one(reg, index);
|
||||
log_misc("mxsuperio", "amHmLpcReadByte Index=0x%02x Reg=0x%02x Data=0x%02x", index, reg,
|
||||
lpc_out->data);
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsuperio_lpc_packet);
|
||||
} break;
|
||||
case IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE: {
|
||||
BYTE index = lpc_packet->index;
|
||||
BYTE reg = lpc_packet->reg;
|
||||
log_misc("mxsuperio", "amHmLpcWriteByte Index=0x%02x Reg=0x%02x Data=0x%02b", index,
|
||||
reg, lpc_packet->data);
|
||||
|
||||
switch (w83791d_bank) {
|
||||
case 0x00: {
|
||||
switch (reg) {
|
||||
case W83627UHG_REG_FAN_CONF:
|
||||
w83627uhg_fanconf = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_FAN_CONF_2:
|
||||
w83627uhg_fanconf_2 = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_CPUFANOUT_VALUE_SELECT:
|
||||
// Just no-op this
|
||||
break;
|
||||
case W83627UHG_REG_CPUFANOUT_TEMP_SRC_SLCT:
|
||||
w83627uhg_cpufanout_src_slct = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_SYSFANOUT_TEMP_SRC_SLCT:
|
||||
w83627uhg_sysfanout_src_slct = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_SYSTIN_TARGET_TEMP:
|
||||
w83627uhg_systin_target = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_CPUTIN_TARGET_TEMP:
|
||||
w83627uhg_cputin_target = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_TARGET_TEMP_TOLERANCE:
|
||||
w83627uhg_target_tolerance = lpc_packet->data;
|
||||
break;
|
||||
case W83627UHG_REG_SYSFANOUT_STOP_VALUE:
|
||||
case W83627UHG_REG_SYSFANOUT_START_VALUE:
|
||||
break;
|
||||
|
||||
case W83791D_REG_BEEP_CTRL_0:
|
||||
// Ignore for now
|
||||
break;
|
||||
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
case W83791D_REG_CONFIG:
|
||||
w83791d_config = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_VBAT_MONITOR_CONTROL:
|
||||
w83791d_vbat_monitor_control = lpc_packet->data;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b0 register: write 0x%02x", reg);
|
||||
// exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
|
||||
case W83791D_NONCRIT_TEMP_1:
|
||||
w83791d_noncrit_t1 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_1:
|
||||
w83791d_crit_t1 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_2:
|
||||
w83791d_noncrit_t2 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_2:
|
||||
w83791d_crit_t2 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_3:
|
||||
w83791d_noncrit_t3 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_3:
|
||||
w83791d_crit_t3 = lpc_packet->data;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x05: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
|
||||
// Used in amHmReadVoltageInternal
|
||||
// What is this??
|
||||
case 0x40:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 0;
|
||||
} break;
|
||||
default:
|
||||
log_warning("mxsuperio", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsuperio() {
|
||||
file_hook_t* mxsuperio = new_file_hook(L"\\\\.\\mxsuperio");
|
||||
mxsuperio->DeviceIoControl = &mxsuperio_DeviceIoControl;
|
||||
|
||||
hook_file(mxsuperio);
|
||||
}
|
||||
|
38
src/micetools/dll/hooks/README.md
Normal file
38
src/micetools/dll/hooks/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# com.c
|
||||
|
||||
Generic hooks for com devices. The main COMs used are:
|
||||
|
||||
- COM 1: Camera
|
||||
- COM 2: NFC
|
||||
- COM 3: Touch
|
||||
- COM 5-8: LEDs
|
||||
|
||||
These are defined in devices/
|
||||
|
||||
# files.c
|
||||
|
||||
Redirection hooks for files. These are used to redirect a number of locations to relative paths, and for `\\\\.\\driver` files.
|
||||
|
||||
# gui.c
|
||||
|
||||
Hooks for drawing over the game
|
||||
|
||||
# logging.c
|
||||
|
||||
Hooks for `[f]printf[_s]`, and event sources.
|
||||
|
||||
# network.c
|
||||
|
||||
Network hooks used to log when outbound TCP connections are made, and to redirect DNS.
|
||||
|
||||
# processes.c
|
||||
|
||||
(Disabled) hooks CreateProcess to re-inject ourself into any child processes too
|
||||
|
||||
# setupapi.c
|
||||
|
||||
Hooks the Setup API functions to inject fake devices (used for amPlatform and amEeprom)
|
||||
|
||||
# time.c
|
||||
|
||||
Hooks a handful of time-setting functions to NOP them
|
@ -1,12 +1,14 @@
|
||||
#include "_hooks.h"
|
||||
|
||||
void hook_all() {
|
||||
hook_logging();
|
||||
hook_gui();
|
||||
hook_setupapi();
|
||||
hook_commio();
|
||||
hook_io();
|
||||
hook_processes();
|
||||
hook_network();
|
||||
hook_time();
|
||||
}
|
||||
#include "_hooks.h"
|
||||
|
||||
void hook_all() {
|
||||
hook_logging();
|
||||
hook_gui();
|
||||
hook_setupapi();
|
||||
hook_commio();
|
||||
hook_io();
|
||||
hook_processes();
|
||||
hook_network();
|
||||
hook_time();
|
||||
hook_registry();
|
||||
hook_drives();
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "com.h"
|
||||
#include "files.h"
|
||||
#include "gui.h"
|
||||
#include "logging.h"
|
||||
#include "network.h"
|
||||
#include "processes.h"
|
||||
#include "setupapi_.h"
|
||||
#include "time.h"
|
||||
|
||||
void hook_all();
|
||||
#pragma once
|
||||
|
||||
#include "com.h"
|
||||
#include "files.h"
|
||||
#include "gui.h"
|
||||
#include "logging.h"
|
||||
#include "network.h"
|
||||
#include "processes.h"
|
||||
#include "setupapi_.h"
|
||||
#include "time.h"
|
||||
#include "registry.h"
|
||||
#include "drive.h"
|
||||
|
||||
void hook_all();
|
||||
|
@ -1,204 +1,181 @@
|
||||
#include "com.h"
|
||||
|
||||
com_hook_t* com_hook_list = NULL;
|
||||
com_hook_t* new_com_hook(BYTE port) {
|
||||
com_hook_t* hook = (com_hook_t*)malloc(sizeof *hook);
|
||||
|
||||
memset(hook->wName, 0, sizeof hook->wName);
|
||||
swprintf(hook->wName, (sizeof hook->wName) / (sizeof hook->wName[0]), L"COM%d", port);
|
||||
memset(hook->wDosName, 0, sizeof hook->wDosName);
|
||||
swprintf(hook->wDosName, (sizeof hook->wDosName) / (sizeof hook->wDosName[0]), L"\\\\.\\COM%d", port);
|
||||
hook->com = port;
|
||||
|
||||
hook->GetCommState = NULL;
|
||||
hook->SetCommState = NULL;
|
||||
hook->GetCommTimeouts = NULL;
|
||||
hook->SetCommTimeouts = NULL;
|
||||
hook->SetupComm = NULL;
|
||||
hook->PurgeComm = NULL;
|
||||
hook->GetCommModemStatus = NULL;
|
||||
hook->WaitCommEvent = NULL;
|
||||
hook->ClearCommError = NULL;
|
||||
|
||||
return hook;
|
||||
};
|
||||
|
||||
void hook_com(com_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE));
|
||||
*hook->virtual_handle = NULL;
|
||||
if (com_hook_list == NULL) {
|
||||
com_hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
com_hook_t* hl = com_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
};
|
||||
|
||||
BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||
log_misc(COMM_LOGGER, "GetCommState(0x%p, 0x%p)", hFile, lpDCB);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->GetCommState == NULL) {
|
||||
log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->GetCommState(hook->data, lpDCB);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueGetCommState(hFile, lpDCB);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||
log_misc(COMM_LOGGER, "SetCommState(0x%p, 0x%p)", hFile, lpDCB);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->SetCommState == NULL) {
|
||||
log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->SetCommState(hook->data, lpDCB);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueSetCommState(hFile, lpDCB);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
|
||||
log_misc(COMM_LOGGER, "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->GetCommTimeouts == NULL) {
|
||||
log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->GetCommTimeouts(hook->data, lpCommTimeouts);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueGetCommTimeouts(hFile, lpCommTimeouts);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
|
||||
log_misc(COMM_LOGGER, "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->SetCommTimeouts == NULL) {
|
||||
log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->SetCommTimeouts(hook->data, lpCommTimeouts);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueSetCommTimeouts(hFile, lpCommTimeouts);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) {
|
||||
log_misc(COMM_LOGGER, "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->SetupComm == NULL) {
|
||||
log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->SetupComm(hook->data, dwInQueue, dwOutQueue);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueSetupComm(hFile, dwInQueue, dwOutQueue);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) {
|
||||
log_misc(COMM_LOGGER, "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->PurgeComm == NULL) {
|
||||
log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->PurgeComm(hook->data, dwFlags);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TruePurgeComm(hFile, dwFlags);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) {
|
||||
log_misc(COMM_LOGGER, "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->GetCommModemStatus == NULL) {
|
||||
log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->GetCommModemStatus(hook->data, lpModelStat);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueGetCommModemStatus(hFile, lpModelStat);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
log_misc(COMM_LOGGER, "WaitCommEvent");
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->WaitCommEvent == NULL) {
|
||||
log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
|
||||
log_misc(COMM_LOGGER, "ClearCommError");
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->ClearCommError == NULL) {
|
||||
log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->ClearCommError(hook->data, lpErrors, lpStat);
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueClearCommError(hFile, lpErrors, lpStat);
|
||||
}
|
||||
|
||||
void hook_commio() {
|
||||
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState, 6);
|
||||
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState, 6);
|
||||
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts, 6);
|
||||
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts, 6);
|
||||
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm, 6);
|
||||
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm, 6);
|
||||
hook("Kernel32.dll", "GetCommModemStatus", FakeGetCommModemStatus, (void**)&TrueGetCommModemStatus, 6);
|
||||
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent, 6);
|
||||
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError, 6);
|
||||
#include "com.h"
|
||||
|
||||
#include "files.h"
|
||||
|
||||
com_hook_t* com_hook_list = NULL;
|
||||
com_hook_t* new_com_hook(BYTE port) {
|
||||
com_hook_t* hook = (com_hook_t*)malloc(sizeof *hook);
|
||||
|
||||
memset(hook->wName, 0, sizeof hook->wName);
|
||||
swprintf(hook->wName, (sizeof hook->wName) / (sizeof hook->wName[0]), L"COM%d", port);
|
||||
memset(hook->wDosName, 0, sizeof hook->wDosName);
|
||||
swprintf(hook->wDosName, (sizeof hook->wDosName) / (sizeof hook->wDosName[0]), L"\\\\.\\COM%d",
|
||||
port);
|
||||
hook->com = port;
|
||||
|
||||
hook->GetCommState = NULL;
|
||||
hook->SetCommState = NULL;
|
||||
hook->GetCommTimeouts = NULL;
|
||||
hook->SetCommTimeouts = NULL;
|
||||
hook->SetupComm = NULL;
|
||||
hook->PurgeComm = NULL;
|
||||
hook->GetCommModemStatus = NULL;
|
||||
hook->WaitCommEvent = NULL;
|
||||
hook->ClearCommError = NULL;
|
||||
|
||||
return hook;
|
||||
}
|
||||
|
||||
void hook_com(com_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE));
|
||||
*hook->virtual_handle = NULL;
|
||||
if (com_hook_list == NULL) {
|
||||
com_hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
com_hook_t* hl = com_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
log_misc(COMM_LOGGER, "GetCommState(0x%p, 0x%p) (%08x)", hFile, lpDCB, hook);
|
||||
|
||||
if (hook != NULL) {
|
||||
if (hook->GetCommState == NULL) {
|
||||
log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->GetCommState(hook->data, lpDCB);
|
||||
}
|
||||
return TrueGetCommState(hFile, lpDCB);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||
log_misc(COMM_LOGGER, "SetCommState(0x%p, 0x%p)", hFile, lpDCB);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->SetCommState == NULL) {
|
||||
log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->SetCommState(hook->data, lpDCB);
|
||||
}
|
||||
|
||||
return TrueSetCommState(hFile, lpDCB);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
|
||||
log_misc(COMM_LOGGER, "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->GetCommTimeouts == NULL) {
|
||||
log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->GetCommTimeouts(hook->data, lpCommTimeouts);
|
||||
}
|
||||
return TrueGetCommTimeouts(hFile, lpCommTimeouts);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
|
||||
log_misc(COMM_LOGGER, "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->SetCommTimeouts == NULL) {
|
||||
log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->SetCommTimeouts(hook->data, lpCommTimeouts);
|
||||
}
|
||||
return TrueSetCommTimeouts(hFile, lpCommTimeouts);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) {
|
||||
log_misc(COMM_LOGGER, "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->SetupComm == NULL) {
|
||||
log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->SetupComm(hook->data, dwInQueue, dwOutQueue);
|
||||
}
|
||||
return TrueSetupComm(hFile, dwInQueue, dwOutQueue);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) {
|
||||
log_misc(COMM_LOGGER, "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->PurgeComm == NULL) {
|
||||
log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->PurgeComm(hook->data, dwFlags);
|
||||
}
|
||||
return TruePurgeComm(hFile, dwFlags);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) {
|
||||
log_misc(COMM_LOGGER, "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->GetCommModemStatus == NULL) {
|
||||
log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->GetCommModemStatus(hook->data, lpModelStat);
|
||||
}
|
||||
return TrueGetCommModemStatus(hFile, lpModelStat);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
log_misc(COMM_LOGGER, "WaitCommEvent(0x%p)", hFile);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->WaitCommEvent == NULL) {
|
||||
log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped);
|
||||
}
|
||||
return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
|
||||
log_trace(COMM_LOGGER, "ClearCommError(0x%p)", hFile);
|
||||
|
||||
com_hook_t* hook = get_handle_com_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->ClearCommError == NULL) {
|
||||
log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", hook->wName);
|
||||
return FALSE;
|
||||
}
|
||||
return hook->ClearCommError(hook->data, lpErrors, lpStat);
|
||||
}
|
||||
return TrueClearCommError(hFile, lpErrors, lpStat);
|
||||
}
|
||||
|
||||
void hook_commio() {
|
||||
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState, 6);
|
||||
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState, 6);
|
||||
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts, 6);
|
||||
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts, 6);
|
||||
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm, 6);
|
||||
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm, 6);
|
||||
hook("Kernel32.dll", "GetCommModemStatus", FakeGetCommModemStatus,
|
||||
(void**)&TrueGetCommModemStatus, 6);
|
||||
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent, 6);
|
||||
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError, 6);
|
||||
}
|
@ -1,49 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
static BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
static BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
|
||||
static BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags);
|
||||
static BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat);
|
||||
static BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat);
|
||||
|
||||
typedef BOOL(FnGetCommState)(void* com, LPDCB lpDCB);
|
||||
typedef BOOL(FnSetCommState)(void* com, LPDCB lpDCB);
|
||||
typedef BOOL(FnGetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
typedef BOOL(FnSetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
typedef BOOL(FnSetupComm)(void* com, DWORD dwInQueue, DWORD dwOutQueue);
|
||||
typedef BOOL(FnPurgeComm)(void* com, DWORD dwFlags);
|
||||
typedef BOOL(FnGetCommModemStatus)(void* com, LPDWORD lpModelStat);
|
||||
typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat);
|
||||
|
||||
typedef struct com_hook {
|
||||
LPHANDLE virtual_handle;
|
||||
WCHAR wName[7]; // max is "COM255"
|
||||
WCHAR wDosName[11]; // max is "\\\\.\\COM255"
|
||||
BYTE com;
|
||||
|
||||
FnGetCommState* GetCommState;
|
||||
FnSetCommState* SetCommState;
|
||||
FnGetCommTimeouts* GetCommTimeouts;
|
||||
FnSetCommTimeouts* SetCommTimeouts;
|
||||
FnSetupComm* SetupComm;
|
||||
FnPurgeComm* PurgeComm;
|
||||
FnGetCommModemStatus* GetCommModemStatus;
|
||||
FnWaitCommEvent* WaitCommEvent;
|
||||
FnClearCommError* ClearCommError;
|
||||
|
||||
void* data;
|
||||
|
||||
struct com_hook* next;
|
||||
} com_hook_t;
|
||||
|
||||
com_hook_t* new_com_hook(BYTE port);
|
||||
void hook_com(com_hook_t* hook);
|
||||
|
||||
void hook_commio();
|
||||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
static BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
static BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
|
||||
static BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags);
|
||||
static BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat);
|
||||
static BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat);
|
||||
|
||||
typedef BOOL(FnGetCommState)(void* com, LPDCB lpDCB);
|
||||
typedef BOOL(FnSetCommState)(void* com, LPDCB lpDCB);
|
||||
typedef BOOL(FnGetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
typedef BOOL(FnSetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
typedef BOOL(FnSetupComm)(void* com, DWORD dwInQueue, DWORD dwOutQueue);
|
||||
typedef BOOL(FnPurgeComm)(void* com, DWORD dwFlags);
|
||||
typedef BOOL(FnGetCommModemStatus)(void* com, LPDWORD lpModelStat);
|
||||
typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat);
|
||||
|
||||
typedef struct com_hook {
|
||||
LPHANDLE virtual_handle;
|
||||
WCHAR wName[16];
|
||||
WCHAR wDosName[16];
|
||||
BYTE com;
|
||||
|
||||
FnGetCommState* GetCommState;
|
||||
FnSetCommState* SetCommState;
|
||||
FnGetCommTimeouts* GetCommTimeouts;
|
||||
FnSetCommTimeouts* SetCommTimeouts;
|
||||
FnSetupComm* SetupComm;
|
||||
FnPurgeComm* PurgeComm;
|
||||
FnGetCommModemStatus* GetCommModemStatus;
|
||||
FnWaitCommEvent* WaitCommEvent;
|
||||
FnClearCommError* ClearCommError;
|
||||
|
||||
void* data;
|
||||
|
||||
struct com_hook* next;
|
||||
} com_hook_t;
|
||||
|
||||
extern com_hook_t* com_hook_list;
|
||||
|
||||
com_hook_t* new_com_hook(BYTE port);
|
||||
void hook_com(com_hook_t* hook);
|
||||
|
||||
void hook_commio();
|
||||
|
398
src/micetools/dll/hooks/drive.c
Normal file
398
src/micetools/dll/hooks/drive.c
Normal file
@ -0,0 +1,398 @@
|
||||
#include "drive.h"
|
||||
|
||||
#include "./files.h"
|
||||
|
||||
BOOL c_drive_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
log_trace("C", "DeviceIOControl %08x", dwIoControlCode);
|
||||
memset(lpOutBuffer, 0, nInBufferSize);
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
|
||||
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
|
||||
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceNumber = 0;
|
||||
return TRUE;
|
||||
case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
|
||||
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->NumberOfDiskExtents = 1;
|
||||
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->Extents[0].StartingOffset.QuadPart = 0;
|
||||
DWORD a = (sizeof(*((VOLUME_DISK_EXTENTS*)lpOutBuffer)));
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
LARGE_INTEGER pd0_file_pointer;
|
||||
BOOL pd0_SetFilePointerEx(void* file, LARGE_INTEGER liDistanceToMove,
|
||||
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) {
|
||||
log_trace("pd0", "Seek 0x%08x", liDistanceToMove.QuadPart);
|
||||
if (dwMoveMethod == FILE_BEGIN)
|
||||
pd0_file_pointer = liDistanceToMove;
|
||||
else
|
||||
pd0_file_pointer.QuadPart += liDistanceToMove.QuadPart;
|
||||
if (lpNewFilePointer) lpNewFilePointer->QuadPart = pd0_file_pointer.QuadPart;
|
||||
return TRUE;
|
||||
}
|
||||
DWORD pd0_SetFilePointer(void* file, LONG liDistanceToMove, PLONG lpDistanceToMoveHigh,
|
||||
DWORD dwMoveMethod) {
|
||||
if (lpDistanceToMoveHigh && *lpDistanceToMoveHigh)
|
||||
log_trace("pd0", "Seek 0x%x%08x", *lpDistanceToMoveHigh, liDistanceToMove);
|
||||
else
|
||||
log_trace("pd0", "Seek 0x%08x", liDistanceToMove);
|
||||
|
||||
if (dwMoveMethod == FILE_BEGIN) {
|
||||
if (lpDistanceToMoveHigh)
|
||||
pd0_file_pointer.HighPart = *lpDistanceToMoveHigh;
|
||||
else
|
||||
pd0_file_pointer.HighPart = 0;
|
||||
pd0_file_pointer.LowPart = liDistanceToMove;
|
||||
} else {
|
||||
pd0_file_pointer.QuadPart += liDistanceToMove;
|
||||
if (lpDistanceToMoveHigh) pd0_file_pointer.HighPart += *lpDistanceToMoveHigh;
|
||||
}
|
||||
return pd0_file_pointer.LowPart;
|
||||
}
|
||||
|
||||
void write_chs(BYTE* chs, WORD cylinder, BYTE head, BYTE sector) {
|
||||
chs[0] = head;
|
||||
chs[1] = sector | ((cylinder >> 8) << 6);
|
||||
chs[2] = cylinder & 0xff;
|
||||
}
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct spd {
|
||||
uint32_t crc;
|
||||
uint8_t version;
|
||||
uint8_t _[11];
|
||||
#pragma pack(1)
|
||||
struct {
|
||||
/*
|
||||
(BCD)
|
||||
1.0 = original0
|
||||
1.1 = original1
|
||||
2.0 = patch0
|
||||
2.1 = patch1
|
||||
3.0 = os
|
||||
4.0 = app_data
|
||||
*/
|
||||
spd_slot_t slot_content;
|
||||
/*
|
||||
Guess: Filesystem type
|
||||
0: Encrypted FAT16
|
||||
1: Decrypted NTFS
|
||||
*/
|
||||
uint8_t uk1;
|
||||
uint16_t block_size;
|
||||
uint32_t block_count;
|
||||
uint8_t __[8];
|
||||
} slots[31];
|
||||
} spd_t;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
uint16_t year;
|
||||
uint8_t mon;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t _;
|
||||
} slot_time_t;
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
char id[4];
|
||||
slot_time_t time;
|
||||
uint32_t version;
|
||||
uint32_t _[2];
|
||||
uint32_t segcount;
|
||||
uint32_t segsize;
|
||||
|
||||
char hw[3];
|
||||
uint8_t instant;
|
||||
slot_time_t orgtime;
|
||||
uint32_t orgversion;
|
||||
uint32_t osver;
|
||||
uint32_t ossegcount;
|
||||
|
||||
uint8_t __[8];
|
||||
} sbr_slot_t;
|
||||
#pragma pack(1)
|
||||
enum {
|
||||
Slot_Check = 0x00, // status=error
|
||||
Slot_Install = 0x01, // status=install -> FAILED TO READ PREMADE BLOCK!!
|
||||
Slot_Complete = 0x02, // status=complete
|
||||
Slot_Empty = 0x03, // status=error
|
||||
Slot_Error = 0x04, // status=error
|
||||
Slot_Invalid = 0xff,
|
||||
};
|
||||
typedef uint8_t slot_status_t;
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
uint32_t crc;
|
||||
uint8_t version;
|
||||
uint8_t _[11 + 16 + 32];
|
||||
uint8_t bootslot;
|
||||
uint8_t __[2];
|
||||
slot_status_t slot_status[5];
|
||||
uint8_t ___[8 + 16 + 32 + 64];
|
||||
sbr_slot_t slot_os;
|
||||
sbr_slot_t slot_original0;
|
||||
sbr_slot_t slot_appdata;
|
||||
sbr_slot_t slot_patch0;
|
||||
sbr_slot_t slot_patch1;
|
||||
} sbr_t;
|
||||
|
||||
sbr_t SegaBootRecord = {
|
||||
.version = SBR_VERSION,
|
||||
.bootslot = 0x02,
|
||||
|
||||
.slot_status = { Slot_Complete, Slot_Complete, Slot_Invalid, Slot_Check, Slot_Complete },
|
||||
|
||||
.slot_os = {
|
||||
// Starts at 0xc5469400
|
||||
// i.e. [partition 6] - (segcount * segsize)
|
||||
// i.e. partition 5 = [dead space] [slot_os]
|
||||
.id = {'A', 'A', 'S', '0'},
|
||||
.time = { 0 },
|
||||
.version = 0x450a01,
|
||||
.segcount = 1745,
|
||||
.segsize = 0x40000,
|
||||
.hw = { 'A', 'A', 'S' },
|
||||
.instant = 0,
|
||||
.osver = 0x450a01,
|
||||
.ossegcount = 0,
|
||||
.orgtime = { 0 },
|
||||
.orgversion = 0x450a01,
|
||||
},
|
||||
.slot_original0 = {
|
||||
// Starts at 0xb065bae00
|
||||
// i.e. [end of disk] - (segcount * segsize)
|
||||
// i.e. partition 9 = [dead space] [slot_original0]
|
||||
|
||||
.id = {'S', 'D', 'E', 'Y'},
|
||||
.time = { 2018, 10, 29, 15, 7, 36 },
|
||||
.version = 0x10061,
|
||||
.segcount = 65082,
|
||||
.segsize = 0x40000,
|
||||
.hw = { 'A', 'A', 'S' },
|
||||
.instant = 0,
|
||||
.osver = 0x450a01,
|
||||
.ossegcount = 1745,
|
||||
.orgtime = { 2018, 10, 29, 15, 7, 36 },
|
||||
.orgversion = 0x10061,
|
||||
},
|
||||
.slot_appdata = { 0 },
|
||||
.slot_patch0 = {
|
||||
// Starts at 0x15e49a000
|
||||
// i.e. [partition 7] - (segcount * segsize)
|
||||
// i.e. partition 6 = [dead space] [something] [patch0]
|
||||
|
||||
.id = { 'S', 'D', 'D', 'Z' },
|
||||
.time = { 2018, 6, 21, 13, 46, 24 },
|
||||
.version = 0x10060,
|
||||
.segcount = 173,
|
||||
.segsize = 0x40000,
|
||||
.hw = { 'A', 'A', 'S' },
|
||||
.instant = 0,
|
||||
.osver = 0,
|
||||
.ossegcount = 0,
|
||||
.orgtime = { 2018, 5, 16, 20, 7, 12 },
|
||||
.orgversion = 0x01005f,
|
||||
},
|
||||
.slot_patch1 = {
|
||||
// Starts at 0x1debcac00
|
||||
// i.e. [partition 8] - (segcount * segsize)
|
||||
// i.e. partition 7 = [dead space] [something] [patch0]
|
||||
|
||||
.id = { 'S', 'D', 'E', 'Y' },
|
||||
.time = { 2018, 11, 16, 19, 4, 48},
|
||||
.version = 0x10062,
|
||||
.segcount = 173,
|
||||
.segsize = 0x40000,
|
||||
.hw = { 'A', 'A', 'S' },
|
||||
.instant = 0,
|
||||
.osver = 0,
|
||||
.ossegcount = 0,
|
||||
.orgtime = { 2018, 10, 29, 15, 7, 36 },
|
||||
.orgversion = 0x10061,
|
||||
},
|
||||
};
|
||||
|
||||
#define BOOT_PARITION_SIZE 0x300B85 // 1.5GB
|
||||
#define RECOVER_PARTITION_SIZE 0x300BC4 // 1.5GB
|
||||
typedef struct {
|
||||
uint32_t size;
|
||||
uint8_t type;
|
||||
spd_slot_t content;
|
||||
} partition_t;
|
||||
partition_t partitions[] = {
|
||||
{ 0x102d83, MBR_FS_FAT16, SPD_OS }, // 512MB OS update
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0
|
||||
{ 0x403947, MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1
|
||||
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData }, // 40GB something
|
||||
{ 0x20014aa, MBR_FS_FAT16, SPD_Original0 }, // 16GB game
|
||||
};
|
||||
#define NUM_PARITIONS (sizeof partitions / sizeof partitions[0])
|
||||
|
||||
#define MBR_LBA_GAP 0x3f // 1 track worth of sectors is claimed for the MBR
|
||||
|
||||
#define BLOCKSIZE 512ll
|
||||
|
||||
#define SPD_OFFSET ((extended_base * BLOCKSIZE) + sizeof(mbr_t))
|
||||
#define SBR0_OFFSET (SPD_OFFSET + sizeof (spd_t))
|
||||
#define SBR1_OFFSET (SBR0_OFFSET + sizeof SegaBootRecord)
|
||||
|
||||
BOOL pd0_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
|
||||
log_info("pd0", "Read %d @ %llx", nNumberOfBytesToRead, pd0_file_pointer.QuadPart);
|
||||
|
||||
uint32_t ext_offset = 0;
|
||||
uint32_t offsets[NUM_PARITIONS];
|
||||
uint32_t extended_base = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE;
|
||||
for (int i = 0; i < NUM_PARITIONS; i++) {
|
||||
offsets[i] = ext_offset;
|
||||
ext_offset += partitions[i].size + MBR_LBA_GAP;
|
||||
}
|
||||
|
||||
printf("%08x\n", offsets[0]);
|
||||
printf("%08x\n", extended_base);
|
||||
|
||||
// MBR (C+Recover+Extend)
|
||||
if (pd0_file_pointer.QuadPart == 0) {
|
||||
mbr_t* mbr = (mbr_t*)lpBuffer;
|
||||
memset(mbr, 0, sizeof *mbr);
|
||||
mbr->sig[0] = 0x55;
|
||||
mbr->sig[1] = 0xAA;
|
||||
|
||||
// 1.5GB C parition
|
||||
mbr->partitions[0].status = MBR_FLAG_BOOTABLE;
|
||||
mbr->partitions[0].type = MBR_FS_NTFS;
|
||||
mbr->partitions[0].lba = MBR_LBA_GAP;
|
||||
mbr->partitions[0].sectors = BOOT_PARITION_SIZE;
|
||||
|
||||
// 1.5GB Recovery
|
||||
mbr->partitions[1].status = MBR_FLAG_NONE;
|
||||
mbr->partitions[1].type = MBR_FS_NTFS;
|
||||
mbr->partitions[1].lba = MBR_LBA_GAP + BOOT_PARITION_SIZE;
|
||||
mbr->partitions[1].sectors = RECOVER_PARTITION_SIZE;
|
||||
|
||||
// Everything else is in an extended
|
||||
mbr->partitions[2].status = MBR_FLAG_NONE;
|
||||
mbr->partitions[2].type = MBR_FS_EXT_LBA;
|
||||
mbr->partitions[2].lba = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE;
|
||||
mbr->partitions[2].sectors = ext_offset;
|
||||
|
||||
*lpNumberOfBytesRead = sizeof *mbr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Extended partitions
|
||||
for (int i = 0; i < NUM_PARITIONS; i++) {
|
||||
if (pd0_file_pointer.QuadPart != ((extended_base + offsets[i]) * BLOCKSIZE)) continue;
|
||||
|
||||
mbr_t* mbr = (mbr_t*)lpBuffer;
|
||||
memset(mbr, 0, sizeof *mbr);
|
||||
mbr->sig[0] = 0x55;
|
||||
mbr->sig[1] = 0xAA;
|
||||
|
||||
mbr->partitions[0].status = MBR_FLAG_NONE;
|
||||
mbr->partitions[0].type = partitions[i].type;
|
||||
mbr->partitions[0].lba = MBR_LBA_GAP;
|
||||
mbr->partitions[0].sectors = partitions[i].size;
|
||||
|
||||
if (i != NUM_PARITIONS - 1) {
|
||||
mbr->partitions[1].status = MBR_FLAG_NONE;
|
||||
mbr->partitions[1].type = MBR_FS_EXT_CHS;
|
||||
mbr->partitions[1].lba = offsets[i + 1];
|
||||
mbr->partitions[1].sectors = partitions[i + 1].size + MBR_LBA_GAP;
|
||||
}
|
||||
|
||||
*lpNumberOfBytesRead = sizeof *mbr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
crc32_build_table();
|
||||
SegaBootRecord.crc = crc32(sizeof SegaBootRecord - 4, &SegaBootRecord.version, 0);
|
||||
|
||||
// SEGA Partition Description
|
||||
if (pd0_file_pointer.QuadPart == SPD_OFFSET) {
|
||||
spd_t* spd = (spd_t*)lpBuffer;
|
||||
spd->version = SPD_VERSION;
|
||||
for (uint8_t i = 0; i < NUM_PARITIONS; i++) {
|
||||
spd->slots[i].block_size = BLOCKSIZE;
|
||||
spd->slots[i].block_count = partitions[i].size;
|
||||
spd->slots[i].slot_content = partitions[i].content;
|
||||
spd->slots[i].uk1 = partitions[i].type == MBR_FS_FAT16 ? 0 : 1;
|
||||
}
|
||||
spd->crc = crc32(sizeof *spd - 4, &(spd->version), 0);
|
||||
|
||||
*lpNumberOfBytesRead = sizeof *spd;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// SEGA Boot Record 0 and 1. The two are a redundant copy of each other
|
||||
if (pd0_file_pointer.QuadPart == SBR0_OFFSET || pd0_file_pointer.QuadPart == SBR1_OFFSET) {
|
||||
memcpy(lpBuffer, &SegaBootRecord, sizeof SegaBootRecord);
|
||||
*lpNumberOfBytesRead = sizeof SegaBootRecord;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Read within a partition
|
||||
if (pd0_file_pointer.QuadPart < MBR_LBA_GAP * BLOCKSIZE) {
|
||||
log_error("pd0", "Read performed within the first track of disk!");
|
||||
} else if (pd0_file_pointer.QuadPart < (MBR_LBA_GAP + BOOT_PARITION_SIZE) * BLOCKSIZE) {
|
||||
log_warning("pd0", "Game attempting to read windows partition!");
|
||||
} else if (pd0_file_pointer.QuadPart <
|
||||
(MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE) * BLOCKSIZE) {
|
||||
log_warning("pd0", "Game attempting to read recovery partition!");
|
||||
} else {
|
||||
for (int i = 0; i < NUM_PARITIONS; i++) {
|
||||
if (pd0_file_pointer.QuadPart <
|
||||
(offsets[i] + MBR_LBA_GAP + extended_base) * BLOCKSIZE) {
|
||||
log_error("pd0", "Read performed within the first track of partition %d!", i + 5);
|
||||
goto warned;
|
||||
} else if (pd0_file_pointer.QuadPart <
|
||||
(offsets[i] + MBR_LBA_GAP + partitions[i].size + extended_base) *
|
||||
BLOCKSIZE) {
|
||||
log_warning("pd0", "Read performed within partition %d", i + 5);
|
||||
goto warned;
|
||||
}
|
||||
}
|
||||
log_error("pd0", "Read to unmapped address: %llx (%d bytes)", pd0_file_pointer.QuadPart,
|
||||
nNumberOfBytesToRead);
|
||||
warned:;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL pd0_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
|
||||
log_warning("pd0", "Write %d @ %llx", nNumberOfBytesToWrite, pd0_file_pointer.QuadPart);
|
||||
|
||||
for (DWORD i = 0; i < nNumberOfBytesToWrite; i += 32) {
|
||||
for (int j = 0; j < 32; j++) {
|
||||
printf("%02x ", ((BYTE*)lpBuffer)[i + j]);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void hook_drives() {
|
||||
file_hook_t* c_drive = new_file_hook(L"\\\\.\\C:");
|
||||
c_drive->DeviceIoControl = &c_drive_DeviceIoControl;
|
||||
|
||||
hook_file(c_drive);
|
||||
|
||||
file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive0");
|
||||
// file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive2063598201");
|
||||
// file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive1811939950");
|
||||
physical_drive_0->SetFilePointerEx = pd0_SetFilePointerEx;
|
||||
physical_drive_0->SetFilePointer = pd0_SetFilePointer;
|
||||
physical_drive_0->ReadFile = pd0_ReadFile;
|
||||
physical_drive_0->WriteFile = pd0_WriteFile;
|
||||
hook_file(physical_drive_0);
|
||||
}
|
43
src/micetools/dll/hooks/drive.h
Normal file
43
src/micetools/dll/hooks/drive.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
void hook_drives();
|
||||
|
||||
// MBR
|
||||
#define MBR_FLAG_NONE 0x00
|
||||
#define MBR_FLAG_BOOTABLE 0x80
|
||||
|
||||
#define MBR_FS_NONE 0x00
|
||||
#define MBR_FS_EXT_CHS 0x05
|
||||
#define MBR_FS_FAT16 0x06
|
||||
#define MBR_FS_NTFS 0x07
|
||||
#define MBR_FS_EXT_LBA 0x0F
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mbr {
|
||||
BYTE bootstrap_code[446];
|
||||
#pragma pack(1)
|
||||
struct {
|
||||
BYTE status;
|
||||
BYTE start_chs[3];
|
||||
BYTE type;
|
||||
BYTE end_chs[3];
|
||||
DWORD lba;
|
||||
DWORD sectors;
|
||||
} partitions[4];
|
||||
BYTE sig[2];
|
||||
} mbr_t;
|
||||
|
||||
// SEGA
|
||||
#define SPD_VERSION 1
|
||||
#define SBR_VERSION 1
|
||||
|
||||
enum spd_slot {
|
||||
SPD_Original0 = 0x10,
|
||||
SPD_Original1 = 0x11,
|
||||
SPD_Patch0 = 0x20,
|
||||
SPD_Patch1 = 0x21,
|
||||
SPD_OS = 0x30,
|
||||
SPD_AppData = 0x40,
|
||||
};
|
||||
typedef uint8_t spd_slot_t;
|
@ -1,256 +1,365 @@
|
||||
#include "files.h"
|
||||
|
||||
HANDLE fake_handle = (HANDLE)0x10000000;
|
||||
|
||||
file_hook_t* file_hook_list = NULL;
|
||||
file_hook_t* new_file_hook(LPCWSTR filename) {
|
||||
file_hook_t* hook = (file_hook_t*)malloc(sizeof(file_hook_t));
|
||||
memset(hook, 0, sizeof(file_hook_t));
|
||||
|
||||
hook->filename = filename;
|
||||
|
||||
return hook;
|
||||
}
|
||||
void hook_file(file_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE));
|
||||
*hook->virtual_handle = NULL;
|
||||
if (file_hook_list == NULL) {
|
||||
file_hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
file_hook_t* hl = file_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
};
|
||||
|
||||
drive_redirect_t DRIVE_REDIRECT_TABLE[] = {
|
||||
{ .drive = "Y:\\", .path = ".\\dev\\Y\\" },
|
||||
// Note: Had tp create last_shime.log
|
||||
{ .drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\" },
|
||||
// {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"},
|
||||
};
|
||||
|
||||
char* redirect_path(char* path) {
|
||||
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
|
||||
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
|
||||
if (strstr(path, row.drive)) {
|
||||
log_misc(HOOKS_LOGGER, "Redirecting '%s' to '%s'", path, row.path);
|
||||
|
||||
size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path);
|
||||
// TODO: Make this not leak memory!
|
||||
char* new_str = (char*)malloc(new_len + 1);
|
||||
strcpy_s(new_str, new_len + 1, row.path);
|
||||
|
||||
char* dst = new_str + strlen(row.path);
|
||||
size_t len = strlen(path) - strlen(row.drive);
|
||||
char* src = path + strlen(row.drive);
|
||||
|
||||
for (; len > 0; len--) (dst++)[0] = (src++)[0];
|
||||
dst[0] = 0;
|
||||
log_misc(HOOKS_LOGGER, "New filename: '%s'", new_str);
|
||||
return new_str;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
||||
HANDLE handle = NULL;
|
||||
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (wcscmp(lpFileName, hook->filename) == 0 ||
|
||||
(hook->altFilename != NULL && wcscmp(lpFileName, hook->altFilename) == 0)) {
|
||||
if (*hook->virtual_handle == NULL) {
|
||||
// TODO: Assign handles better!
|
||||
*hook->virtual_handle = fake_handle;
|
||||
((size_t)fake_handle)++;
|
||||
}
|
||||
handle = *hook->virtual_handle;
|
||||
|
||||
log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
break;
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
if (handle == NULL) {
|
||||
handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, hTemplateFile);
|
||||
}
|
||||
|
||||
log_misc(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
||||
lpFileName = redirect_path((char*)lpFileName);
|
||||
|
||||
WCHAR wideFileName[MAX_PATH + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1);
|
||||
|
||||
HANDLE result = FakeCreateFileW((LPCWSTR)&wideFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
log_misc(HOOKS_LOGGER, "^-> CreateFileA(%s) -> 0x%p", lpFileName, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
log_misc(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice, dwIoControlCode,
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hDevice) {
|
||||
if (hook->DeviceIoControl) {
|
||||
// TODO: Less jank
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
|
||||
BOOL ret = hook->DeviceIoControl(hook->data, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
|
||||
nOutBufferSize, lpBytesReturned, lpOverlapped);
|
||||
if (ret && lpOverlapped && lpBytesReturned) {
|
||||
lpOverlapped->InternalHigh = *lpBytesReturned;
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
// log_warning(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, -, -, -, -, 0, 0)", hDevice, dwIoControlCode);
|
||||
|
||||
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
|
||||
lpBytesReturned, lpOverlapped);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->SetFilePointer) {
|
||||
return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
|
||||
DWORD dwMoveMethod) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->SetFilePointerEx) {
|
||||
return hook->SetFilePointerEx(hook->data, liDistanceToMove, lpNewFilePointer, dwMoveMethod);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "SetFilePointerEx(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->GetFileSizeEx) {
|
||||
return hook->GetFileSizeEx(hook->data, lpFileSize);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueGetFileSizeEx(hFile, lpFileSize);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->WriteFile) {
|
||||
return hook->WriteFile(hook->data, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten,
|
||||
lpOverlapped);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (*hook->virtual_handle == hFile) {
|
||||
if (hook->ReadFile) {
|
||||
return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hObject != NULL && *hook->virtual_handle == hObject) {
|
||||
log_misc("file", "close %08x", hObject);
|
||||
return TRUE;
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueCloseHandle(hObject);
|
||||
}
|
||||
|
||||
int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) {
|
||||
path = redirect_path((char*)path);
|
||||
return True_stat64i32(path, buffer);
|
||||
};
|
||||
|
||||
void hook_io() {
|
||||
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5);
|
||||
|
||||
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6);
|
||||
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6);
|
||||
|
||||
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
|
||||
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
|
||||
hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx, 6);
|
||||
hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6);
|
||||
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6);
|
||||
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx, 6);
|
||||
|
||||
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5);
|
||||
}
|
||||
#include "files.h"
|
||||
|
||||
open_hook_t* open_hooks_list = NULL;
|
||||
HANDLE open_hook(file_hook_t* file_hook, com_hook_t* com_hook) {
|
||||
open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t));
|
||||
memset(opened, 0, sizeof *opened);
|
||||
|
||||
opened->file_hook = file_hook;
|
||||
opened->com_hook = com_hook;
|
||||
|
||||
CHAR path[MAX_PATH];
|
||||
GetModuleFileNameA(NULL, path, MAX_PATH);
|
||||
HANDLE handle =
|
||||
_CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
log_error(HOOKS_LOGGER, "Failed to create dummy handle: %03x", GetLastError());
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
opened->handle = handle;
|
||||
opened->next = open_hooks_list;
|
||||
open_hooks_list = opened;
|
||||
|
||||
return handle;
|
||||
}
|
||||
void close_hook(HANDLE handle) {
|
||||
if (handle == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
_CloseHandle(handle);
|
||||
|
||||
open_hook_t* opened = NULL;
|
||||
open_hook_t* root = open_hooks_list;
|
||||
if (open_hooks_list->handle == handle) {
|
||||
open_hook_t* next = open_hooks_list->next;
|
||||
free(open_hooks_list);
|
||||
open_hooks_list = next;
|
||||
return;
|
||||
}
|
||||
|
||||
while (root != NULL) {
|
||||
if (root->next && root->next->handle == handle) {
|
||||
opened = root->next;
|
||||
root->next = opened->next;
|
||||
free(opened);
|
||||
return;
|
||||
}
|
||||
root = root->next;
|
||||
}
|
||||
}
|
||||
file_hook_t* get_handle_file_hook(HANDLE handle) {
|
||||
open_hook_t* root = open_hooks_list;
|
||||
while (root != NULL) {
|
||||
if (root->handle == handle) return root->file_hook;
|
||||
root = root->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
com_hook_t* get_handle_com_hook(HANDLE handle) {
|
||||
open_hook_t* root = open_hooks_list;
|
||||
while (root != NULL) {
|
||||
if (root->handle == handle) return root->com_hook;
|
||||
root = root->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_hook_t* file_hook_list = NULL;
|
||||
file_hook_t* new_file_hook(LPCWSTR filename) {
|
||||
file_hook_t* hook = (file_hook_t*)malloc(sizeof(file_hook_t));
|
||||
memset(hook, 0, sizeof *hook);
|
||||
|
||||
hook->filename = filename;
|
||||
|
||||
return hook;
|
||||
}
|
||||
void hook_file(file_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
if (file_hook_list == NULL) {
|
||||
file_hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
file_hook_t* hl = file_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
};
|
||||
|
||||
drive_redirect_t DRIVE_REDIRECT_TABLE[] = {
|
||||
{ .drive = "Y:\\", .path = ".\\dev\\Y\\" },
|
||||
// Note: Had tp create last_shime.log
|
||||
{ .drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\" },
|
||||
// {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"},
|
||||
|
||||
{ .drive = "C:\\\\Windows\\\\System32\\", .path = "Sys32" },
|
||||
{ .drive = "C:\\\\WINDOWS\\\\system32\\", .path = "Sys32" },
|
||||
};
|
||||
|
||||
LPCSTR redirect_path(LPCSTR path) {
|
||||
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
|
||||
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
|
||||
if (strstr(path, row.drive)) {
|
||||
log_misc(HOOKS_LOGGER, "Redirecting '%s' to '%s'", path, row.path);
|
||||
|
||||
size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path);
|
||||
// TODO: Make this not leak memory!
|
||||
char* new_str = (char*)malloc(new_len + 1);
|
||||
strcpy_s(new_str, new_len + 1, row.path);
|
||||
|
||||
char* dst = new_str + strlen(row.path);
|
||||
size_t len = strlen(path) - strlen(row.drive);
|
||||
const char* src = path + strlen(row.drive);
|
||||
|
||||
for (; len > 0; len--) (dst++)[0] = (src++)[0];
|
||||
dst[0] = 0;
|
||||
log_misc(HOOKS_LOGGER, "New filename: '%s'", new_str);
|
||||
return new_str;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
LPCWSTR redirect_path_w(LPCWSTR path) {
|
||||
return path;
|
||||
// TODO: THIS!!
|
||||
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
|
||||
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
|
||||
if (wcsstr(path, row.drive)) {
|
||||
log_misc(HOOKS_LOGGER, "Redirecting '%ls' to '%ls'", path, row.path);
|
||||
|
||||
size_t new_len = wcslen(path) - wcslen(row.drive) + wcslen(row.path);
|
||||
// TODO: Make this not leak memory!
|
||||
wchar_t* new_str = (wchar_t*)malloc((new_len + 1) * 2);
|
||||
wcscpy_s(new_str, new_len + 1, row.path);
|
||||
|
||||
wchar_t* dst = new_str + wcslen(row.path) * 2;
|
||||
size_t len = wcslen(path) - wcslen(row.drive);
|
||||
const wchar_t* src = path + wcslen(row.drive) * 2;
|
||||
|
||||
for (; len > 0; len--) {
|
||||
(dst++)[0] = (src++)[0];
|
||||
(dst++)[0] = (src++)[0];
|
||||
}
|
||||
dst[0] = 0;
|
||||
log_misc(HOOKS_LOGGER, "New filename: '%ls'", new_str);
|
||||
return new_str;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void find_hooks(LPCWSTR lpFileName, file_hook_t** found_fh, com_hook_t** found_ch) {
|
||||
file_hook_t* file_hook = file_hook_list;
|
||||
while (file_hook != NULL) {
|
||||
if (wcscmp(lpFileName, file_hook->filename) == 0 ||
|
||||
(file_hook->altFilename != NULL && wcscmp(lpFileName, file_hook->altFilename) == 0)) {
|
||||
*found_fh = file_hook;
|
||||
break;
|
||||
}
|
||||
file_hook = file_hook->next;
|
||||
}
|
||||
|
||||
com_hook_t* com_hook = com_hook_list;
|
||||
while (com_hook != NULL) {
|
||||
if (wcscmp(lpFileName, com_hook->wName) == 0 ||
|
||||
wcscmp(lpFileName, com_hook->wDosName) == 0) {
|
||||
*found_ch = com_hook;
|
||||
break;
|
||||
}
|
||||
com_hook = com_hook->next;
|
||||
}
|
||||
};
|
||||
|
||||
HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile) {
|
||||
file_hook_t* found_fh = NULL;
|
||||
com_hook_t* found_ch = NULL;
|
||||
find_hooks(lpFileName, &found_fh, &found_ch);
|
||||
if (found_fh != NULL || found_ch != NULL) {
|
||||
HANDLE handle = open_hook(found_fh, found_ch);
|
||||
log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
lpFileName = redirect_path_w(lpFileName);
|
||||
|
||||
HANDLE handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
log_misc(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile) {
|
||||
WCHAR wideFileName[MAX_PATH + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1);
|
||||
|
||||
file_hook_t* found_fh = NULL;
|
||||
com_hook_t* found_ch = NULL;
|
||||
find_hooks(wideFileName, &found_fh, &found_ch);
|
||||
if (found_fh != NULL || found_ch != NULL) {
|
||||
HANDLE handle = open_hook(found_fh, found_ch);
|
||||
log_info(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
lpFileName = redirect_path(lpFileName);
|
||||
|
||||
HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
log_misc(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
|
||||
// lpFileName = redirect_path(lpFileName);
|
||||
|
||||
// HANDLE result =
|
||||
// FakeCreateFileW((LPCWSTR)&wideFileName, dwDesiredAccess, dwShareMode,
|
||||
// lpSecurityAttributes,
|
||||
// dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
// log_trace(HOOKS_LOGGER, "^-> CreateFileA(%s) -> 0x%p", lpFileName, result);
|
||||
// return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
file_hook_t* hook = get_handle_file_hook(hDevice);
|
||||
if (hook != NULL) {
|
||||
if (hook->DeviceIoControl) {
|
||||
// TODO: Less jank
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
|
||||
BOOL ret =
|
||||
hook->DeviceIoControl(hook->data, dwIoControlCode, lpInBuffer, nInBufferSize,
|
||||
lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped);
|
||||
if (ret && lpOverlapped && lpBytesReturned) {
|
||||
lpOverlapped->InternalHigh = *lpBytesReturned;
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
log_trace(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice,
|
||||
dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
|
||||
nOutBufferSize, lpBytesReturned, lpOverlapped);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
|
||||
DWORD dwMoveMethod) {
|
||||
file_hook_t* hook = get_handle_file_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->SetFilePointer) {
|
||||
return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh,
|
||||
dwMoveMethod);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove,
|
||||
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) {
|
||||
file_hook_t* hook = get_handle_file_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->SetFilePointerEx) {
|
||||
return hook->SetFilePointerEx(hook->data, liDistanceToMove, lpNewFilePointer,
|
||||
dwMoveMethod);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "SetFilePointerEx(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
|
||||
file_hook_t* hook = get_handle_file_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->GetFileSizeEx) {
|
||||
return hook->GetFileSizeEx(hook->data, lpFileSize);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TrueGetFileSizeEx(hFile, lpFileSize);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
|
||||
log_trace("file", "WriteFile(%08x)", hFile);
|
||||
file_hook_t* hook = get_handle_file_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->WriteFile) {
|
||||
return hook->WriteFile(hook->data, lpBuffer, nNumberOfBytesToWrite,
|
||||
lpNumberOfBytesWritten, lpOverlapped);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten,
|
||||
lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
|
||||
file_hook_t* hook = get_handle_file_hook(hFile);
|
||||
if (hook != NULL) {
|
||||
if (hook->ReadFile) {
|
||||
return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
|
||||
lpOverlapped);
|
||||
} else {
|
||||
log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
|
||||
file_hook_t* hook = get_handle_file_hook(hObject);
|
||||
if (hook != NULL) {
|
||||
log_misc("file", "close %08x", hObject);
|
||||
close_hook(hObject);
|
||||
return TRUE;
|
||||
}
|
||||
return TrueCloseHandle(hObject);
|
||||
}
|
||||
|
||||
int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) {
|
||||
path = redirect_path((char*)path);
|
||||
return True_stat64i32(path, buffer);
|
||||
};
|
||||
|
||||
void hook_io() {
|
||||
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5);
|
||||
|
||||
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6);
|
||||
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6);
|
||||
|
||||
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
|
||||
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
|
||||
hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx,
|
||||
6);
|
||||
hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6);
|
||||
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6);
|
||||
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx, 6);
|
||||
|
||||
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5);
|
||||
}
|
||||
|
@ -1,72 +1,98 @@
|
||||
#pragma once
|
||||
#include "../common.h"
|
||||
|
||||
static HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||
static HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||
|
||||
static BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
static DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
|
||||
DWORD dwMoveMethod);
|
||||
static BOOL(WINAPI* TrueSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
|
||||
DWORD dwMoveMethod);
|
||||
// logging needs access to WriteFile, so we can't static it!
|
||||
BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize);
|
||||
static BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject);
|
||||
|
||||
typedef BOOL(FnDeviceIoControl)(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef DWORD(FnSetFilePointer)(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
|
||||
typedef BOOL(FnSetFilePointerEx)(void* file, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
|
||||
DWORD dwMoveMethod);
|
||||
typedef BOOL(FnWriteFile)(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
typedef BOOL(FnReadFile)(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef BOOL(FnGetFileSizeEx)(void* file, PLARGE_INTEGER lpFileSize);
|
||||
|
||||
static int(WINAPIV* True_stat64i32)(const char* path, struct _stat64i32* buffer);
|
||||
|
||||
#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile)
|
||||
#define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile)
|
||||
#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle)
|
||||
#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW)
|
||||
|
||||
typedef struct drive_redirect {
|
||||
const CHAR* drive;
|
||||
const CHAR* path;
|
||||
} drive_redirect_t;
|
||||
|
||||
typedef struct file_hook {
|
||||
LPCWSTR filename;
|
||||
LPCWSTR altFilename;
|
||||
|
||||
FnDeviceIoControl* DeviceIoControl;
|
||||
FnSetFilePointer* SetFilePointer;
|
||||
FnSetFilePointerEx* SetFilePointerEx;
|
||||
FnWriteFile* WriteFile;
|
||||
FnReadFile* ReadFile;
|
||||
FnGetFileSizeEx* GetFileSizeEx;
|
||||
|
||||
void* data;
|
||||
|
||||
LPHANDLE virtual_handle;
|
||||
struct file_hook* next;
|
||||
} file_hook_t;
|
||||
|
||||
file_hook_t* new_file_hook(LPCWSTR filename);
|
||||
void hook_file(file_hook_t* hook);
|
||||
void hook_io();
|
||||
#pragma once
|
||||
#include "../common.h"
|
||||
#include "com.h"
|
||||
|
||||
static HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
static HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
|
||||
static BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer,
|
||||
DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
static DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove,
|
||||
PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
|
||||
static BOOL(WINAPI* TrueSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove,
|
||||
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod);
|
||||
// logging needs access to WriteFile, so we can't static it!
|
||||
BOOL(WINAPI* TrueWriteFile)
|
||||
(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize);
|
||||
static BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject);
|
||||
|
||||
typedef BOOL(FnDeviceIoControl)(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef DWORD(FnSetFilePointer)(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
|
||||
DWORD dwMoveMethod);
|
||||
typedef BOOL(FnSetFilePointerEx)(void* file, LARGE_INTEGER liDistanceToMove,
|
||||
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod);
|
||||
typedef BOOL(FnWriteFile)(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
||||
typedef BOOL(FnReadFile)(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef BOOL(FnGetFileSizeEx)(void* file, PLARGE_INTEGER lpFileSize);
|
||||
|
||||
typedef struct _stat64i32 _stat64i32_t;
|
||||
static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer);
|
||||
|
||||
#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile)
|
||||
#define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile)
|
||||
#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle)
|
||||
#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW)
|
||||
#define _CreateFileA (TrueCreateFileA ? TrueCreateFileA : CreateFileA)
|
||||
|
||||
typedef struct drive_redirect {
|
||||
const CHAR* drive;
|
||||
const CHAR* path;
|
||||
} drive_redirect_t;
|
||||
|
||||
typedef struct drive_redirect_w {
|
||||
const WCHAR* drive;
|
||||
const WCHAR* path;
|
||||
} drive_redirect_w_t;
|
||||
|
||||
typedef struct file_hook {
|
||||
LPCWSTR filename;
|
||||
LPCWSTR altFilename;
|
||||
|
||||
FnDeviceIoControl* DeviceIoControl;
|
||||
FnSetFilePointer* SetFilePointer;
|
||||
FnSetFilePointerEx* SetFilePointerEx;
|
||||
FnWriteFile* WriteFile;
|
||||
FnReadFile* ReadFile;
|
||||
FnGetFileSizeEx* GetFileSizeEx;
|
||||
|
||||
void* data;
|
||||
|
||||
LPHANDLE virtual_handle;
|
||||
struct file_hook* next;
|
||||
} file_hook_t;
|
||||
|
||||
typedef struct open_hook {
|
||||
HANDLE handle;
|
||||
file_hook_t* file_hook;
|
||||
com_hook_t* com_hook;
|
||||
struct open_hook* next;
|
||||
} open_hook_t;
|
||||
|
||||
extern file_hook_t* file_hook_list;
|
||||
|
||||
file_hook_t* new_file_hook(LPCWSTR filename);
|
||||
void hook_file(file_hook_t* hook);
|
||||
void hook_io();
|
||||
|
||||
void close_hook(HANDLE handle);
|
||||
file_hook_t* get_handle_file_hook(HANDLE handle);
|
||||
com_hook_t* get_handle_com_hook(HANDLE handle);
|
||||
|
@ -1,99 +1,103 @@
|
||||
#include "../util/_util.h"
|
||||
#include "logging.h"
|
||||
|
||||
char* trim_string(char* string) {
|
||||
size_t len = strlen(string) - 1;
|
||||
|
||||
DWORD oldProt;
|
||||
while (len > 0 && (string[len] == '\n' || string[len] == '\r')) {
|
||||
// TODO: Reassess this. Suspect it may be causing issues.
|
||||
// Make sure we can write! This is a terrible hack, but it does work.
|
||||
VirtualProtect(string + len, 1, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
string[len--] = '\0';
|
||||
VirtualProtect(string + len + 1, 1, oldProt, &oldProt);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
#define WORK_FORMAT_MAX 1024
|
||||
char format_buf[WORK_FORMAT_MAX]; // Will do. We guard against overflow in Fake[f]printf
|
||||
|
||||
int WINAPIV Fakeprintf(const char* _Format, ...) {
|
||||
int flen = strlen(_Format);
|
||||
if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) {
|
||||
strcpy_s(format_buf, WORK_FORMAT_MAX, _Format);
|
||||
format_buf[flen - 1] = 0;
|
||||
_Format = format_buf;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, _Format);
|
||||
|
||||
int ret = vlog_game("printf", _Format, args);
|
||||
|
||||
va_end(args);
|
||||
return vlog_game("printf", _Format, args);
|
||||
}
|
||||
|
||||
int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) {
|
||||
int flen = strlen(_Format);
|
||||
if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) {
|
||||
strcpy_s(format_buf, WORK_FORMAT_MAX, _Format);
|
||||
format_buf[flen - 1] = 0;
|
||||
_Format = format_buf;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, _Format);
|
||||
|
||||
int ret = vlog_game("fprintf", _Format, args);
|
||||
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WINAPIV Fakefprintf_s(FILE* _Stream, const char* _Format, ...) {
|
||||
va_list args;
|
||||
va_start(args, _Format);
|
||||
|
||||
int ret = vlog_game("fprintf_s", _Format, args);
|
||||
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
HANDLE WINAPI FakeRegisterEventSourceA(LPCSTR lpUNCServerName, LPCSTR lpSourceName) { return (HANDLE)0xDEADBEEF; }
|
||||
|
||||
BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
|
||||
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData) {
|
||||
switch (wType) {
|
||||
case EVENTLOG_SUCCESS:
|
||||
case EVENTLOG_AUDIT_SUCCESS:
|
||||
for (int i = 0; i < wNumStrings; i++) log_misc("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
case EVENTLOG_AUDIT_FAILURE:
|
||||
case EVENTLOG_ERROR_TYPE:
|
||||
for (int i = 0; i < wNumStrings; i++) log_error("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
case EVENTLOG_WARNING_TYPE:
|
||||
for (int i = 0; i < wNumStrings; i++) log_warning("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
case EVENTLOG_INFORMATION_TYPE:
|
||||
default:
|
||||
for (int i = 0; i < wNumStrings; i++) log_info("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
|
||||
|
||||
// static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString);
|
||||
// VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s", lpOutputString); }
|
||||
|
||||
void hook_logging() {
|
||||
hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf, 6);
|
||||
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf, 6);
|
||||
hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s, 6);
|
||||
|
||||
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA, (void**)&TrueRegisterEventSourceA, 6);
|
||||
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA, 6);
|
||||
hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource, (void**)&TrueDeregisterEventSource, 6);
|
||||
}
|
||||
#include "../util/_util.h"
|
||||
#include "logging.h"
|
||||
|
||||
char* trim_string(char* string) {
|
||||
size_t len = strlen(string) - 1;
|
||||
|
||||
DWORD oldProt;
|
||||
while (len > 0 && (string[len] == '\n' || string[len] == '\r')) {
|
||||
// TODO: Reassess this. Suspect it may be causing issues.
|
||||
// Make sure we can write! This is a terrible hack, but it does work.
|
||||
VirtualProtect(string + len, 1, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
string[len--] = '\0';
|
||||
VirtualProtect(string + len + 1, 1, oldProt, &oldProt);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
#define WORK_FORMAT_MAX 1024
|
||||
char format_buf[WORK_FORMAT_MAX]; // Will do. We guard against overflow in Fake[f]printf
|
||||
|
||||
int WINAPIV Fakeprintf(const char* _Format, ...) {
|
||||
size_t flen = strlen(_Format);
|
||||
if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) {
|
||||
strcpy_s(format_buf, WORK_FORMAT_MAX, _Format);
|
||||
format_buf[flen - 1] = 0;
|
||||
_Format = format_buf;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, _Format);
|
||||
|
||||
int ret = vlog_game("printf", _Format, args);
|
||||
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) {
|
||||
size_t flen = strlen(_Format);
|
||||
if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) {
|
||||
strcpy_s(format_buf, WORK_FORMAT_MAX, _Format);
|
||||
format_buf[flen - 1] = 0;
|
||||
_Format = format_buf;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, _Format);
|
||||
|
||||
int ret = vlog_game("fprintf", _Format, args);
|
||||
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WINAPIV Fakefprintf_s(FILE* _Stream, const char* _Format, ...) {
|
||||
va_list args;
|
||||
va_start(args, _Format);
|
||||
|
||||
int ret = vlog_game("fprintf_s", _Format, args);
|
||||
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int WINAPIV Fakevfprintf_s(FILE* _Stream, const char* _Format, va_list _ArgList) {
|
||||
return vlog_game("vfprintf_s", _Format, _ArgList);
|
||||
}
|
||||
HANDLE WINAPI FakeRegisterEventSourceA(LPCSTR lpUNCServerName, LPCSTR lpSourceName) { return (HANDLE)0xDEADBEEF; }
|
||||
|
||||
BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
|
||||
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData) {
|
||||
switch (wType) {
|
||||
case EVENTLOG_SUCCESS:
|
||||
case EVENTLOG_AUDIT_SUCCESS:
|
||||
for (int i = 0; i < wNumStrings; i++) log_misc("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
case EVENTLOG_AUDIT_FAILURE:
|
||||
case EVENTLOG_ERROR_TYPE:
|
||||
for (int i = 0; i < wNumStrings; i++) log_error("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
case EVENTLOG_WARNING_TYPE:
|
||||
for (int i = 0; i < wNumStrings; i++) log_warning("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
case EVENTLOG_INFORMATION_TYPE:
|
||||
default:
|
||||
for (int i = 0; i < wNumStrings; i++) log_info("evtlog", trim_string((char*)lpStrings[i]));
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
|
||||
|
||||
// static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString);
|
||||
// VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s", lpOutputString); }
|
||||
|
||||
void hook_logging() {
|
||||
hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf, 6);
|
||||
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf, 6);
|
||||
hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s, 6);
|
||||
hook("MSVCR90.DLL", "vfprintf_s", Fakevfprintf_s, (void**)&Truevfprintf_s, 6);
|
||||
|
||||
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA, (void**)&TrueRegisterEventSourceA, 6);
|
||||
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA, 6);
|
||||
hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource, (void**)&TrueDeregisterEventSource, 6);
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
#pragma once
|
||||
// #include "../common.h"
|
||||
#include <Windows.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName);
|
||||
static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
|
||||
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData);
|
||||
static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog);
|
||||
|
||||
int(WINAPIV* Trueprintf)(const char* _Format, ...);
|
||||
static int(WINAPIV* Truefprintf)(FILE* _File, const char* _Format, ...);
|
||||
static int(WINAPIV* Truefprintf_s)(FILE* _Stream, const char* _Format, ...);
|
||||
|
||||
void hook_logging();
|
||||
#pragma once
|
||||
// #include "../common.h"
|
||||
#include <Windows.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName);
|
||||
static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
|
||||
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData);
|
||||
static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog);
|
||||
|
||||
int(WINAPIV* Trueprintf)(const char* _Format, ...);
|
||||
static int(WINAPIV* Truefprintf)(FILE* _File, const char* _Format, ...);
|
||||
static int(WINAPIV* Truefprintf_s)(FILE* _Stream, const char* _Format, ...);
|
||||
static int(WINAPIV* Truevfprintf_s)(FILE* _Stream, const char* _Format, va_list _ArgList);
|
||||
|
||||
void hook_logging();
|
||||
|
@ -1,11 +1,13 @@
|
||||
hooks_files = files(
|
||||
'_hooks.c',
|
||||
'com.c',
|
||||
'files.c',
|
||||
'gui.c',
|
||||
'logging.c',
|
||||
'network.c',
|
||||
'processes.c',
|
||||
'setupapi.c',
|
||||
'time.c',
|
||||
hooks_files = files(
|
||||
'_hooks.c',
|
||||
'com.c',
|
||||
'files.c',
|
||||
'gui.c',
|
||||
'logging.c',
|
||||
'network.c',
|
||||
'processes.c',
|
||||
'setupapi.c',
|
||||
'time.c',
|
||||
'registry.c',
|
||||
'drive.c',
|
||||
)
|
@ -1,85 +1,133 @@
|
||||
#include "network.h"
|
||||
|
||||
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
|
||||
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
|
||||
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
|
||||
log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff,
|
||||
addr & 0xff, port);
|
||||
return True_connect(s, name, namelen);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) {
|
||||
DWORD ret = TrueGetIfTable(pIfTable, pdwSize, bOrder);
|
||||
if (ret == NO_ERROR) {
|
||||
for (size_t i = 0; i < pIfTable->dwNumEntries; i++) {
|
||||
pIfTable->table[i].bPhysAddr[0] = 0x00;
|
||||
pIfTable->table[i].bPhysAddr[1] = 0xD0;
|
||||
pIfTable->table[i].bPhysAddr[2] = 0xF1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
const char* INTERCEPT_DNS[] = {
|
||||
"naominet.jp", // Startup
|
||||
"ib.naominet.jp", // Billing
|
||||
"aime.naominet.jp", // Aime (duh)
|
||||
"tenporouter.loc", // Routers
|
||||
"bbrouter.loc", //
|
||||
"mobirouter.loc", //
|
||||
"dslrouter.loc", //
|
||||
};
|
||||
|
||||
DNS_RECORDA dummy_record;
|
||||
|
||||
unsigned char SPOOF_IP[4] = { 10, 0, 0, 4 };
|
||||
DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra, PDNS_RECORDA* ppQueryResults,
|
||||
PVOID* pReserved) {
|
||||
if (ppQueryResults) {
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(pszName, INTERCEPT_DNS[i]) == 0) {
|
||||
log_info("dns", "Replacing %s with %hhu.%hhu.%hhu.%hhu", pszName, SPOOF_IP[0], SPOOF_IP[1], SPOOF_IP[2],
|
||||
SPOOF_IP[3]);
|
||||
|
||||
// We only support replacing at most one address, but that's all we'll ever need to!
|
||||
(*ppQueryResults) = &dummy_record;
|
||||
(*ppQueryResults)->pNext = NULL;
|
||||
(*ppQueryResults)->wType = DNS_TYPE_A;
|
||||
(*ppQueryResults)->Data.A.IpAddress =
|
||||
(SPOOF_IP[0]) | (SPOOF_IP[1] << 8) | (SPOOF_IP[2] << 16) | (SPOOF_IP[3] << 24);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
log_warning("dns", "DNS passthrough for %s", pszName);
|
||||
return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved);
|
||||
};
|
||||
|
||||
INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFOA lpProtocolInfo,
|
||||
LPSOCKADDR lpAddress, LPINT lpAddressLength) {
|
||||
log_misc("dns", "(WSA)DNS lookup for %s", AddressString);
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(AddressString, INTERCEPT_DNS[i]) == 0) {
|
||||
log_info("dns", "(WSA)Replacing %s with %hhu.%hhu.%hhu.%hhu", AddressString, SPOOF_IP[0], SPOOF_IP[1],
|
||||
SPOOF_IP[2], SPOOF_IP[3]);
|
||||
|
||||
lpAddress->sa_family = AF_INET;
|
||||
// ... :)
|
||||
lpAddress->sa_data[2] = SPOOF_IP[0];
|
||||
lpAddress->sa_data[3] = SPOOF_IP[1];
|
||||
lpAddress->sa_data[4] = SPOOF_IP[2];
|
||||
lpAddress->sa_data[5] = SPOOF_IP[3];
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
log_warning("dns", "(WSA)DNS passthrough for %s", AddressString);
|
||||
return TrueWSAStringToAddressA(AddressString, AddressFamily, lpProtocolInfo, lpAddress, lpAddressLength);
|
||||
}
|
||||
|
||||
void hook_network() {
|
||||
hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect, 5);
|
||||
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA, (void**)&TrueWSAStringToAddressA, 5);
|
||||
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable, 5);
|
||||
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A, 5);
|
||||
}
|
||||
#include "network.h"
|
||||
|
||||
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
|
||||
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
|
||||
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
|
||||
log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff, addr & 0xff, port);
|
||||
return True_connect(s, name, namelen);
|
||||
}
|
||||
|
||||
static uint8_t spoof_mac[6] = { 0xD8, 0xBB, 0xC1, 0x0A, 0x2F, 0x1D };
|
||||
#define IF_INDEX 1
|
||||
DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) {
|
||||
log_info("network", "Injecting fake IfTable");
|
||||
|
||||
MIB_IFROW* row;
|
||||
uint32_t nbytes;
|
||||
|
||||
if (pdwSize == NULL) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
nbytes = *pdwSize;
|
||||
*pdwSize = sizeof(*row) + sizeof(DWORD);
|
||||
|
||||
if (pIfTable == NULL || nbytes < sizeof(*row) + sizeof(DWORD)) {
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
pIfTable->dwNumEntries = 1;
|
||||
|
||||
row = pIfTable->table;
|
||||
memset(row, 0, sizeof(*row));
|
||||
|
||||
wcscpy_s(row->wszName, _countof(row->wszName), L"RING2 Ethernet");
|
||||
row->dwIndex = IF_INDEX;
|
||||
row->dwType = IF_TYPE_ETHERNET_CSMACD;
|
||||
row->dwMtu = 4200;
|
||||
row->dwSpeed = 1000000000;
|
||||
row->dwPhysAddrLen = sizeof(spoof_mac);
|
||||
memcpy(row->bPhysAddr, spoof_mac, sizeof(spoof_mac));
|
||||
row->dwAdminStatus = 1;
|
||||
row->dwOperStatus = IF_OPER_STATUS_OPERATIONAL;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// DWORD ret = TrueGetIfTable(pIfTable, pdwSize, bOrder);
|
||||
// if (ret == NO_ERROR) {
|
||||
// for (size_t i = 0; i < pIfTable->dwNumEntries; i++) {
|
||||
// pIfTable->table[i].bPhysAddr[0] = 0x00;
|
||||
// pIfTable->table[i].bPhysAddr[1] = 0xD0;
|
||||
// pIfTable->table[i].bPhysAddr[2] = 0xF1;
|
||||
// }
|
||||
// }
|
||||
// return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
unsigned char address[4];
|
||||
} dns;
|
||||
dns INTERCEPT_DNS[] = {
|
||||
// Startup
|
||||
{ "naominet.jp", { 192, 168, 103, 254 } },
|
||||
// Billing
|
||||
{ "ib.naominet.jp", { 192, 168, 103, 254 } },
|
||||
// Aime
|
||||
{ "aime.naominet.jp", { 192, 168, 103, 254 } },
|
||||
// Routers (ping targets)
|
||||
{ "tenporouter.loc", { 192, 168, 103, 254 } },
|
||||
{ "bbrouter.loc", { 192, 168, 103, 254 } }, // Must match tenporouter
|
||||
{ "mobirouter.loc", { 192, 168, 103, 254 } },
|
||||
{ "dslrouter.loc", { 192, 168, 103, 254 } },
|
||||
};
|
||||
|
||||
DNS_RECORDA dummy_record;
|
||||
|
||||
DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra,
|
||||
PDNS_RECORDA* ppQueryResults, PVOID* pReserved) {
|
||||
if (ppQueryResults) {
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
|
||||
#define spoof (INTERCEPT_DNS[i].address)
|
||||
log_info("dns", "Replacing %s with %hhu.%hhu.%hhu.%hhu", pszName, spoof[0],
|
||||
spoof[1], spoof[2], spoof[3]);
|
||||
|
||||
// We only support replacing at most one address, but that's all we'll ever need to!
|
||||
(*ppQueryResults) = &dummy_record;
|
||||
(*ppQueryResults)->pNext = NULL;
|
||||
(*ppQueryResults)->wType = DNS_TYPE_A;
|
||||
(*ppQueryResults)->Data.A.IpAddress =
|
||||
(spoof[0]) | (spoof[1] << 8) | (spoof[2] << 16) | (spoof[3] << 24);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
#undef spoof
|
||||
}
|
||||
}
|
||||
}
|
||||
log_warning("dns", "DNS passthrough for %s", pszName);
|
||||
return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved);
|
||||
};
|
||||
|
||||
INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
|
||||
LPWSAPROTOCOL_INFOA lpProtocolInfo, LPSOCKADDR lpAddress,
|
||||
LPINT lpAddressLength) {
|
||||
log_misc("dns", "(WSA)DNS lookup for %s", AddressString);
|
||||
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
|
||||
if (strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) {
|
||||
#define spoof (INTERCEPT_DNS[i].address)
|
||||
log_info("dns", "(WSA)Replacing %s with %hhu.%hhu.%hhu.%hhu", AddressString, spoof[0],
|
||||
spoof[1], spoof[2], spoof[3]);
|
||||
|
||||
lpAddress->sa_family = AF_INET;
|
||||
// ... :)
|
||||
lpAddress->sa_data[2] = spoof[0];
|
||||
lpAddress->sa_data[3] = spoof[1];
|
||||
lpAddress->sa_data[4] = spoof[2];
|
||||
lpAddress->sa_data[5] = spoof[3];
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
#undef spoof
|
||||
}
|
||||
}
|
||||
log_warning("dns", "(WSA)DNS passthrough for %s", AddressString);
|
||||
return TrueWSAStringToAddressA(AddressString, AddressFamily, lpProtocolInfo, lpAddress,
|
||||
lpAddressLength);
|
||||
}
|
||||
|
||||
void hook_network() {
|
||||
hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect, 5);
|
||||
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA,
|
||||
(void**)&TrueWSAStringToAddressA, 7);
|
||||
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable, 5);
|
||||
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A, 5);
|
||||
}
|
||||
|
@ -1,33 +1,43 @@
|
||||
#include "processes.h"
|
||||
|
||||
const wchar_t* HOOK_BINARIES[] = {
|
||||
L"app\\ALLNetProc.exe",
|
||||
L"app\\CameraUploader.exe",
|
||||
L"app\\GmSync.exe",
|
||||
};
|
||||
|
||||
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||
log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||
|
||||
CHAR applicationName[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName, NULL, NULL);
|
||||
|
||||
HANDLE child;
|
||||
if (lpCommandLine != NULL) {
|
||||
CHAR commandLine[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL, NULL);
|
||||
child = start_and_inject(applicationName, commandLine, MICELIB, false);
|
||||
} else {
|
||||
child = start_and_inject(applicationName, NULL, MICELIB, false);
|
||||
}
|
||||
|
||||
return child != NULL;
|
||||
}
|
||||
|
||||
void hook_processes() {
|
||||
// hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6);
|
||||
}
|
||||
#include "processes.h"
|
||||
|
||||
const wchar_t* HOOK_BINARIES[] = {
|
||||
L"app\\ALLNetProc.exe",
|
||||
L"app\\CameraUploader.exe",
|
||||
L"app\\GmSync.exe",
|
||||
};
|
||||
|
||||
#define DISABLE_PROC_SPAWNING
|
||||
|
||||
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||
// #ifdef DISABLE_PROC_SPAWNING
|
||||
// log_error("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||
// return FALSE;
|
||||
// #else
|
||||
log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||
|
||||
CHAR applicationName[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName,
|
||||
NULL, NULL);
|
||||
|
||||
HANDLE child;
|
||||
if (lpCommandLine != NULL) {
|
||||
CHAR commandLine[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL,
|
||||
NULL);
|
||||
child = start_and_inject(applicationName, commandLine, MICELIB, false);
|
||||
} else {
|
||||
child = start_and_inject(applicationName, NULL, MICELIB, false);
|
||||
}
|
||||
|
||||
return !FAILED(child);
|
||||
// #endif
|
||||
}
|
||||
|
||||
void hook_processes() {
|
||||
hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6);
|
||||
}
|
||||
|
5
src/micetools/dll/hooks/registry.c
Normal file
5
src/micetools/dll/hooks/registry.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include "registry.h"
|
||||
|
||||
void hook_registry() {
|
||||
|
||||
}
|
4
src/micetools/dll/hooks/registry.h
Normal file
4
src/micetools/dll/hooks/registry.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
void hook_registry();
|
@ -1,25 +1,26 @@
|
||||
subdir('drivers')
|
||||
subdir('devices')
|
||||
subdir('hooks')
|
||||
|
||||
shared_library(
|
||||
'mice',
|
||||
name_prefix: '',
|
||||
vs_module_defs: 'mice.def',
|
||||
sources: [
|
||||
'util/log.c',
|
||||
'util/hook.c',
|
||||
|
||||
drivers_files,
|
||||
devices_files,
|
||||
hooks_files,
|
||||
|
||||
'comdevice.c',
|
||||
|
||||
'dllmain.c',
|
||||
],
|
||||
link_with: [
|
||||
dmi_lib,
|
||||
mice_lib,
|
||||
]
|
||||
)
|
||||
subdir('drivers')
|
||||
subdir('devices')
|
||||
subdir('hooks')
|
||||
|
||||
shared_library(
|
||||
'mice',
|
||||
name_prefix: '',
|
||||
vs_module_defs: 'mice.def',
|
||||
sources: [
|
||||
'util/log.c',
|
||||
'util/hook.c',
|
||||
|
||||
drivers_files,
|
||||
devices_files,
|
||||
hooks_files,
|
||||
|
||||
'comdevice.c',
|
||||
|
||||
'dllmain.c',
|
||||
],
|
||||
link_with: [
|
||||
dmi_lib,
|
||||
mice_lib,
|
||||
amlib,
|
||||
]
|
||||
)
|
||||
|
@ -1,30 +1,55 @@
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsmbus_request_packet_ {
|
||||
BYTE status;
|
||||
BYTE prt;
|
||||
WORD addr;
|
||||
WORD reg;
|
||||
BYTE dlen;
|
||||
BYTE data[32];
|
||||
} mxsmbus_request_packet;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsmbus_i2c_packet_ {
|
||||
BYTE status;
|
||||
BYTE prt;
|
||||
BYTE addr;
|
||||
BYTE reg;
|
||||
BYTE dlen;
|
||||
BYTE data[32];
|
||||
} mxsmbus_i2c_packet;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsuperio_lpc_packet_ {
|
||||
BYTE index;
|
||||
BYTE reg;
|
||||
BYTE data;
|
||||
} mxsuperio_lpc_packet;
|
||||
enum mxsbus_status { MXSBUS_OKAY = 0 };
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
// PCA9535 (DIPSW)
|
||||
#define PCA9535_WRITE 0x04
|
||||
#define PCA9535_READ 0x05
|
||||
|
||||
#define PCA9535_IN0 0x00
|
||||
#define PCA9535_IN1 0x01
|
||||
#define PCA9535_OUT0 0x02
|
||||
#define PCA9535_OUT1 0x03
|
||||
#define PCA9535_INV0 0x04
|
||||
#define PCA9535_INV1 0x05
|
||||
#define PCA9535_CONF0 0x06
|
||||
#define PCA9535_CONF1 0x07
|
||||
|
||||
#define SMBUS_PCA9535 0x20
|
||||
#define SMBUS_EEPROM 0x57 // Doesn't line up with manual!
|
||||
|
||||
#define SMBUS_DDR2_DIMM_A1 0x000 // what does 0xA0 mean?
|
||||
#define SMBUS_DDR2_DIMM_B1 0x010 // what does 0xA4 mean?
|
||||
#define SMBUS_EEPROM_ 0x0AE // = AT24C64AN
|
||||
#define SMBUS_ICS9LPRS908 0xfff // Unknown
|
||||
#define SMBUS_W83627UHG 0xfff // Unknown; hwmon. Possibly 0x2e or 0x4e
|
||||
#define SMBUS_UPI_UP6261BM8 0xfff // Unknown; vref
|
||||
#define SMBUS_UPI_ISL6322CR 0xfff // Unknown; vrm
|
||||
// SMBUS is send onto the mezzanine board!
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsmbus_request_packet_ {
|
||||
BYTE status;
|
||||
BYTE prt;
|
||||
WORD addr;
|
||||
WORD reg;
|
||||
BYTE dlen;
|
||||
BYTE data[32];
|
||||
} mxsmbus_request_packet;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsmbus_i2c_packet_ {
|
||||
BYTE status;
|
||||
BYTE prt;
|
||||
BYTE addr;
|
||||
BYTE reg;
|
||||
BYTE dlen;
|
||||
BYTE data[32];
|
||||
} mxsmbus_i2c_packet;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsuperio_lpc_packet_ {
|
||||
BYTE index;
|
||||
BYTE reg;
|
||||
BYTE data;
|
||||
} mxsuperio_lpc_packet;
|
||||
enum mxsbus_status { MXSBUS_OKAY = 0 };
|
||||
|
@ -1,144 +1,186 @@
|
||||
#include "log.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../hooks/logging.h"
|
||||
|
||||
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
||||
|
||||
BOOL HAS_COLOUR = FALSE;
|
||||
|
||||
char _log_prelude[64];
|
||||
char* log_prelude() {
|
||||
time_t rawtime;
|
||||
struct tm timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
localtime_s(&timeinfo, &rawtime);
|
||||
|
||||
strftime(_log_prelude, sizeof _log_prelude, "[%Y/%m/%d %H:%M:%S] ", &timeinfo);
|
||||
return _log_prelude;
|
||||
}
|
||||
|
||||
HANDLE LOG_FILE = NULL;
|
||||
VOID trace_hook(char* output);
|
||||
CRITICAL_SECTION logger_lock;
|
||||
|
||||
int _do_log(const char* caller, const char* level, const char* format, va_list args, bool toStdout, char* colour) {
|
||||
EnterCriticalSection(&logger_lock);
|
||||
int len = snprintf(NULL, 0, "%s%s:%s:", log_prelude(), level, caller) + vsnprintf(NULL, 0, format, args);
|
||||
char* buf = (char*)malloc(len + 2);
|
||||
if (!buf) {
|
||||
LeaveCriticalSection(&logger_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrote_a = snprintf(buf, len, "%s%s:%s:", log_prelude(), level, caller);
|
||||
int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args);
|
||||
buf[len] = '\n';
|
||||
buf[len + 1] = '\0';
|
||||
|
||||
// No +1 here to not get the \n
|
||||
if (toStdout) {
|
||||
HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (HAS_COLOUR) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, colour, strlen(colour), NULL, NULL);
|
||||
if (sout != INVALID_HANDLE_VALUE) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, buf, len, NULL, NULL);
|
||||
puts(HAS_COLOUR ? "\033[0m" : "");
|
||||
}
|
||||
#ifdef LOG_TO_FILE
|
||||
if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE)
|
||||
(TrueWriteFile ? TrueWriteFile : WriteFile)(LOG_FILE, buf, len + 1, NULL, NULL);
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
|
||||
LeaveCriticalSection(&logger_lock);
|
||||
return wrote_b;
|
||||
}
|
||||
int vlog_misc(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(caller, "M", format, args, LOG_MISC, "\033[90m");
|
||||
}
|
||||
int log_misc(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_misc(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_info(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(caller, "I", format, args, LOG_INFO, "\033[97m");
|
||||
}
|
||||
int log_info(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_info(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_warning(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(caller, "W", format, args, LOG_WARNING, "\033[33m");
|
||||
}
|
||||
int log_warning(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_warning(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_error(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(caller, "E", format, args, LOG_ERROR, "\033[91m");
|
||||
}
|
||||
int log_error(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_error(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_game(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(caller, "G", format, args, LOG_GAME, "\033[96m");
|
||||
}
|
||||
int log_game(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_game(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
VOID trace_hook(char* output) {
|
||||
output[strcspn(output, "\n")] = 0;
|
||||
log_error("trace", output);
|
||||
}
|
||||
|
||||
void setup_logging() {
|
||||
// Force stdio even for GUI applications
|
||||
AttachConsole(ATTACH_PARENT_PROCESS);
|
||||
if (GetStdHandle(STD_INPUT_HANDLE)) {
|
||||
freopen("CONIN$", "r", stdin);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
}
|
||||
if (GetStdHandle(STD_OUTPUT_HANDLE)) {
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
}
|
||||
if (GetStdHandle(STD_ERROR_HANDLE)) {
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
}
|
||||
|
||||
// Enable colour in CMD
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode))
|
||||
HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
InitializeCriticalSection(&logger_lock);
|
||||
|
||||
if (LOG_FILE == NULL)
|
||||
LOG_FILE = CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
}
|
||||
#include "log.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../hooks/logging.h"
|
||||
|
||||
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
||||
|
||||
BOOL HAS_COLOUR = FALSE;
|
||||
|
||||
char _log_prelude[64];
|
||||
char* log_prelude() {
|
||||
time_t rawtime;
|
||||
struct tm timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
localtime_s(&timeinfo, &rawtime);
|
||||
|
||||
strftime(_log_prelude, sizeof _log_prelude, "[%Y/%m/%d %H:%M:%S] ", &timeinfo);
|
||||
return _log_prelude;
|
||||
}
|
||||
|
||||
HANDLE LOG_FILE = NULL;
|
||||
VOID trace_hook(char* output);
|
||||
CRITICAL_SECTION logger_lock;
|
||||
|
||||
char* log_colours[] = {
|
||||
"", // Always
|
||||
"\033[96m", // Game
|
||||
"\033[91m", // Error
|
||||
"\033[33m", // Warning
|
||||
"\033[97m", // Info
|
||||
"\033[90m", // Misc
|
||||
"\033[90m", // Trace
|
||||
};
|
||||
#define LOG_PREFIXES "!GEWIMT"
|
||||
|
||||
void logcb(LPCSTR param_1) { log_error("logcb", param_1); }
|
||||
|
||||
extern WCHAR exePath[MAX_PATH + 1];
|
||||
int _do_log(BYTE log_level, const char* caller, const char* format, va_list args) {
|
||||
if (wcscmp(exePath, L"mxnetwork.exe") == 0) {
|
||||
// *((DWORD*)(0x004438e8)) = (DWORD)(&logcb);
|
||||
*((DWORD*)(0x004438e8)) = 0x00000000;
|
||||
}
|
||||
|
||||
char prefix = LOG_PREFIXES[log_level];
|
||||
|
||||
EnterCriticalSection(&logger_lock);
|
||||
int len = snprintf(NULL, 0, "%s%c:%s:", log_prelude(), prefix, caller) +
|
||||
vsnprintf(NULL, 0, format, args);
|
||||
char* buf = (char*)malloc(len + 2);
|
||||
if (!buf) {
|
||||
LeaveCriticalSection(&logger_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wrote_a = snprintf(buf, len, "%s%c:%s:", log_prelude(), prefix, caller);
|
||||
int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args);
|
||||
buf[len] = '\n';
|
||||
buf[len + 1] = '\0';
|
||||
|
||||
// No +1 here to not get the \n
|
||||
if (LOG_LEVEL >= log_level) {
|
||||
HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (HAS_COLOUR)
|
||||
(TrueWriteFile ? TrueWriteFile : WriteFile)(sout, log_colours[log_level],
|
||||
strlen(log_colours[log_level]), NULL, NULL);
|
||||
if (sout != INVALID_HANDLE_VALUE)
|
||||
(TrueWriteFile ? TrueWriteFile : WriteFile)(sout, buf, len, NULL, NULL);
|
||||
puts(HAS_COLOUR ? "\033[0m" : "");
|
||||
}
|
||||
#ifdef LOG_TO_FILE
|
||||
if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE)
|
||||
(TrueWriteFile ? TrueWriteFile : WriteFile)(LOG_FILE, buf, len + 1, NULL, NULL);
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
|
||||
LeaveCriticalSection(&logger_lock);
|
||||
return wrote_b;
|
||||
}
|
||||
int vlog_trace(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(LOG_TRACE, caller, format, args);
|
||||
}
|
||||
int log_trace(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_trace(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_misc(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(LOG_MISC, caller, format, args);
|
||||
}
|
||||
int log_misc(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_misc(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_info(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(LOG_INFO, caller, format, args);
|
||||
}
|
||||
int log_info(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_info(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_warning(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(LOG_WARNING, caller, format, args);
|
||||
}
|
||||
int log_warning(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_warning(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_error(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(LOG_ERROR, caller, format, args);
|
||||
}
|
||||
int log_error(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_error(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
int vlog_game(const char* caller, const char* format, va_list args) {
|
||||
return _do_log(LOG_GAME, caller, format, args);
|
||||
}
|
||||
int log_game(const char* caller, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vlog_game(caller, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
VOID trace_hook(char* output) {
|
||||
output[strcspn(output, "\n")] = 0;
|
||||
log_error("trace", output);
|
||||
}
|
||||
|
||||
void setup_logging() {
|
||||
// Force stdio even for GUI applications
|
||||
// TODO: Is there a more robust way to check if we have a proper stdio?
|
||||
AttachConsole(ATTACH_PARENT_PROCESS);
|
||||
if (GetStdHandle(STD_ERROR_HANDLE) > (HANDLE)0x10) {
|
||||
FILE* newstream;
|
||||
if (GetStdHandle(STD_INPUT_HANDLE)) {
|
||||
freopen_s(&newstream, "CONIN$", "r", stdin);
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
}
|
||||
if (GetStdHandle(STD_OUTPUT_HANDLE)) {
|
||||
freopen_s(&newstream, "CONOUT$", "w", stdout);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
}
|
||||
if (GetStdHandle(STD_ERROR_HANDLE)) {
|
||||
freopen_s(&newstream, "CONOUT$", "w", stderr);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable colour in CMD
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode))
|
||||
HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
InitializeCriticalSection(&logger_lock);
|
||||
|
||||
#ifdef LOG_TO_FILE
|
||||
if (LOG_FILE == NULL)
|
||||
LOG_FILE =
|
||||
CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
#endif
|
||||
}
|
||||
|
@ -1,32 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG_MISC FALSE
|
||||
#define LOG_INFO TRUE
|
||||
#define LOG_WARNING TRUE
|
||||
#define LOG_ERROR TRUE
|
||||
#define LOG_GAME TRUE
|
||||
|
||||
// #define LOG_TO_FILE
|
||||
|
||||
#define COMM_LOGGER "comm"
|
||||
#define HOOKS_LOGGER "hooks"
|
||||
#define BOOT_LOGGER "boot"
|
||||
|
||||
extern CRITICAL_SECTION logger_lock;
|
||||
|
||||
int log_misc(const char* caller, const char* format, ...);
|
||||
int log_info(const char* caller, const char* format, ...);
|
||||
int log_warning(const char* caller, const char* format, ...);
|
||||
int log_error(const char* caller, const char* format, ...);
|
||||
int log_game(const char* caller, const char* format, ...);
|
||||
|
||||
int vlog_misc(const char* caller, const char* format, va_list args);
|
||||
int vlog_info(const char* caller, const char* format, va_list args);
|
||||
int vlog_warning(const char* caller, const char* format, va_list args);
|
||||
int vlog_error(const char* caller, const char* format, va_list args);
|
||||
int vlog_game(const char* caller, const char* format, va_list args);
|
||||
|
||||
void setup_logging();
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG_GAME 1
|
||||
#define LOG_ERROR 2
|
||||
#define LOG_WARNING 3
|
||||
#define LOG_INFO 4
|
||||
#define LOG_MISC 5
|
||||
#define LOG_TRACE 6
|
||||
|
||||
#define LOG_LEVEL LOG_TRACE
|
||||
|
||||
// #define LOG_TO_FILE
|
||||
|
||||
#define COMM_LOGGER "comm"
|
||||
#define HOOKS_LOGGER "hooks"
|
||||
#define BOOT_LOGGER "boot"
|
||||
|
||||
extern CRITICAL_SECTION logger_lock;
|
||||
|
||||
int log_trace(const char* caller, const char* format, ...);
|
||||
int log_misc(const char* caller, const char* format, ...);
|
||||
int log_info(const char* caller, const char* format, ...);
|
||||
int log_warning(const char* caller, const char* format, ...);
|
||||
int log_error(const char* caller, const char* format, ...);
|
||||
int log_game(const char* caller, const char* format, ...);
|
||||
|
||||
int vlog_trace(const char* caller, const char* format, va_list args);
|
||||
int vlog_misc(const char* caller, const char* format, va_list args);
|
||||
int vlog_info(const char* caller, const char* format, va_list args);
|
||||
int vlog_warning(const char* caller, const char* format, va_list args);
|
||||
int vlog_error(const char* caller, const char* format, va_list args);
|
||||
int vlog_game(const char* caller, const char* format, va_list args);
|
||||
|
||||
void setup_logging();
|
||||
|
46
src/micetools/dll/w83627uhg.h
Normal file
46
src/micetools/dll/w83627uhg.h
Normal file
@ -0,0 +1,46 @@
|
||||
#define W83627UHG_REG_SYSFANOUT_FREQUENCY 0x00
|
||||
#define W83627UHG_REG_SYSFANOUT_VALUE_SELECT 0x01
|
||||
#define W83627UHG_REG_CPUFANOUT_FREQUENCY 0x02
|
||||
#define W83627UHG_REG_CPUFANOUT_VALUE_SELECT 0x03
|
||||
#define W83627UHG_REG_FAN_CONF 0x04
|
||||
#define W83627UHG_REG_SYSTIN_TARGET_TEMP 0x05
|
||||
#define W83627UHG_REG_CPUTIN_TARGET_TEMP 0x06
|
||||
#define W83627UHG_REG_TARGET_TEMP_TOLERANCE 0x07
|
||||
#define W83627UHG_REG_SYSFANOUT_STOP_VALUE 0x08
|
||||
#define W83627UHG_REG_CPUFANOUT_STOP_VALUE 0x09
|
||||
#define W83627UHG_REG_SYSFANOUT_START_VALUE 0x0a
|
||||
#define W83627UHG_REG_CPUFANOUT_START_VALUE 0x0b
|
||||
#define W83627UHG_REG_SYSFANOUT_STOP_TIME 0x0c
|
||||
#define W83627UHG_REG_CPUFANOUT_STOP_TIME 0x0d
|
||||
#define W83627UHG_REG_FANOUT_STEPDOWN_TIME 0x0e
|
||||
#define W83627UHG_REG_FANOUT_STEPUP_TIME 0x0f
|
||||
#define W83627UHG_REG_FAN_CONF_2 0x12
|
||||
#define W83627UHG_REG_OVT_CONF 0x18
|
||||
|
||||
#define W83627UHG_REG_CONFIG 0x40
|
||||
#define W83627UHG_REG_ISR_1 0x41
|
||||
#define W83627UHG_REG_ISR_2 0x42
|
||||
#define W83627UHG_REG_SMI_MASK_1 0x43
|
||||
#define W83627UHG_REG_SMI_MASK_2 0x44
|
||||
#define W83627UHG_REG_SMI_MASK_3 0x46
|
||||
#define W83627UHG_REG_FAN_DIVISOR 0x47
|
||||
#define W83627UHG_REG_SERIAL_BUS_ADDR 0x48
|
||||
#define W83627UHG_REG_CPUFANOUT_TEMP_SRC_SLCT 0x49
|
||||
#define W83627UHG_REG_SYSFANOUT_TEMP_SRC_SLCT 0x4a
|
||||
#define W83627UHG_REG_FAN_DIVISOR_2 0x4b
|
||||
#define W83627UHG_REG_SMI_OVT_CTRL 0x4c
|
||||
#define W83627UHG_REG_FAN_IN_OUT_CTRL 0x4d
|
||||
#define W83627UHG_REG_WINBOND_ID 0x4f
|
||||
|
||||
#define W83627UHG_REG_BEEP_CTRL_1 0x56
|
||||
#define W83627UHG_REG_BEEP_CTRL_2 0x57
|
||||
#define W83627UHG_REG_CHIP_ID 0x58
|
||||
#define W83627UHG_REG_DIODE_SELECT_REG 0x59
|
||||
|
||||
#define W83627UHG_REG_VBAT_MON_CTRL 0x5d
|
||||
#define W83627UHG_REG_CRIT_TEMP_EN 0x5e
|
||||
|
||||
#define W83627UHG_REG_CPUFANOUT_MAX_OUT 0x67
|
||||
#define W83627UHG_REG_CPUFANOUT_OUT_STEP 0x68
|
||||
#define W83627UHG_REG_SYSFANOUT_CRIT_TEMP 0x6b
|
||||
#define W83627UHG_REG_CPUFANOUT_CRIT_TEMP 0x6c
|
@ -1,75 +1,102 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "locate.h"
|
||||
|
||||
const char* VERSION = "0.0-pre";
|
||||
|
||||
bool boot_delay = false;
|
||||
bool gametest = false;
|
||||
char exe_name[MAX_PATH + 1] = "";
|
||||
|
||||
void print_help(char* exe) {
|
||||
fprintf(stderr, "Usage: %s [-h] [-t] [-b executable.exe] [-d]\n", exe);
|
||||
fprintf(stderr, " -h: Print this help message and exit\n");
|
||||
fprintf(stderr, " -t: Start the game in test mode\n");
|
||||
fprintf(stderr, " -b: Specify the game binary to use\n");
|
||||
fprintf(stderr, " -d: Wait for a debugger to attach when starting\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void parse_cmdline(int argc, char* argv[]) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
} else if (strcmp(argv[i], "-b") == 0) {
|
||||
if (i + 1 == argc) print_help(argv[0]);
|
||||
char* val = argv[++i];
|
||||
memcpy(exe_name, val, strlen(val) + 1);
|
||||
} else if (strcmp(argv[i], "-d") == 0) {
|
||||
boot_delay = true;
|
||||
} else if (strcmp(argv[i], "-t") == 0) {
|
||||
gametest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Micetools version: %s\n", VERSION);
|
||||
|
||||
parse_cmdline(argc, argv);
|
||||
|
||||
if (exe_name[0] == '\0') {
|
||||
if (!locate_game(exe_name, MAX_PATH + 1)) {
|
||||
fprintf(stderr, "Fatal: Failed to locate a game\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
DWORD dwAttrib = GetFileAttributes(exe_name);
|
||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
fprintf(stderr, "Fatal: %s: no such file found\n", exe_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char* cmdline = gametest ? ". gametest" : "";
|
||||
fprintf(stderr, "exec: %s %s\n", exe_name, cmdline);
|
||||
|
||||
char micepath[MAX_PATH + 1];
|
||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||
fprintf(stderr, "Fatal: Failed to locate micelib\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE game_proc = start_and_inject(exe_name, cmdline, micepath, boot_delay);
|
||||
if (!game_proc) return -1;
|
||||
|
||||
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
|
||||
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
|
||||
} else {
|
||||
fprintf(stderr, "Shutting down\n");
|
||||
CloseHandle(game_proc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "locate.h"
|
||||
|
||||
const char* VERSION = "0.0-pre";
|
||||
|
||||
bool boot_delay = false;
|
||||
bool gametest = false;
|
||||
bool designviewer = false;
|
||||
bool spriteviewer = false;
|
||||
bool noisetest = false;
|
||||
char exe_name[MAX_PATH + 1] = "";
|
||||
char commandline[MAX_PATH + 1] = "";
|
||||
|
||||
void print_help(char* exe) {
|
||||
fprintf(stderr, "Usage: %s [-h] [-t] [-b executable.exe] [-d]\n", exe);
|
||||
fprintf(stderr, " -h: Print this help message and exit\n");
|
||||
fprintf(stderr, " -b: Specify the game binary to use\n");
|
||||
fprintf(stderr, " -d: Wait for a debugger to attach when starting\n");
|
||||
fprintf(stderr, " -t: Start the game in test mode\n");
|
||||
fprintf(stderr, " -dv: Start the game in design viewer mode\n");
|
||||
fprintf(stderr, " -sv: Start the game in sprite viewer mode\n");
|
||||
fprintf(stderr, " -nt: Start the game in noisetest mode\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void parse_cmdline(int argc, char* argv[]) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
} else if (strcmp(argv[i], "-b") == 0) {
|
||||
if (i + 1 == argc) print_help(argv[0]);
|
||||
char* val = argv[++i];
|
||||
memcpy(exe_name, val, strlen(val) + 1);
|
||||
} else if (strcmp(argv[i], "--mice-d") == 0) {
|
||||
boot_delay = true;
|
||||
} else if (strcmp(argv[i], "-t") == 0) {
|
||||
gametest = true;
|
||||
} else if (strcmp(argv[i], "-dv") == 0) {
|
||||
designviewer = true;
|
||||
} else if (strcmp(argv[i], "-sv") == 0) {
|
||||
spriteviewer = true;
|
||||
} else if (strcmp(argv[i], "-nt") == 0) {
|
||||
noisetest = true;
|
||||
} else {
|
||||
if (commandline[0] == 0)
|
||||
strncpy_s(commandline, strlen(argv[i]), argv[i], sizeof commandline);
|
||||
else
|
||||
snprintf(commandline, sizeof commandline, "%s %s", commandline, argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Micetools version: %s\n", VERSION);
|
||||
|
||||
parse_cmdline(argc, argv);
|
||||
|
||||
if (exe_name[0] == '\0') {
|
||||
if (!locate_game(exe_name, MAX_PATH + 1)) {
|
||||
fprintf(stderr, "Fatal: Failed to locate a game\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
DWORD dwAttrib = GetFileAttributes(exe_name);
|
||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
fprintf(stderr, "Fatal: %s: no such file found\n", exe_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char* cmdline_mode = gametest ? ". gametest"
|
||||
: designviewer ? ". designviewer"
|
||||
: spriteviewer ? ". spriteviewer"
|
||||
: noisetest ? ". noisetest"
|
||||
: "";
|
||||
char cmdline[MAX_PATH + 1];
|
||||
if (commandline[0] == 0)
|
||||
snprintf(cmdline, sizeof cmdline, "%s", cmdline_mode);
|
||||
else
|
||||
snprintf(cmdline, sizeof cmdline, "%s %s", cmdline_mode, commandline);
|
||||
fprintf(stderr, "exec: %s %s\n", exe_name, cmdline);
|
||||
|
||||
char micepath[MAX_PATH + 1];
|
||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||
fprintf(stderr, "Fatal: Failed to locate micelib\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE game_proc = start_and_inject(exe_name, cmdline, micepath, boot_delay);
|
||||
if (!game_proc) return -1;
|
||||
|
||||
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
|
||||
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
|
||||
} else {
|
||||
fprintf(stderr, "Shutting down\n");
|
||||
CloseHandle(game_proc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
88
src/micetools/lib/am/amEeprom.c
Normal file
88
src/micetools/lib/am/amEeprom.c
Normal file
@ -0,0 +1,88 @@
|
||||
#include "amEeprom.h"
|
||||
#include "../mice/crc.h"
|
||||
|
||||
HANDLE amEepromCreateDeviceFile(const GUID *guid, LPCSTR resource, DWORD member_index) {
|
||||
SP_DEVICE_INTERFACE_DATA interface_data;
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A interface_detail[204];
|
||||
|
||||
if (!guid) return INVALID_HANDLE_VALUE;
|
||||
|
||||
HDEVINFO DeviceInfoSet =
|
||||
SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
|
||||
if (DeviceInfoSet == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
|
||||
|
||||
interface_data.cbSize = 0x1c;
|
||||
BOOL s;
|
||||
s = SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, guid, member_index, &interface_data);
|
||||
if (!s) goto fail;
|
||||
|
||||
interface_detail[0].cbSize = 5;
|
||||
s = SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, &interface_data, interface_detail,
|
||||
sizeof interface_detail, NULL, NULL);
|
||||
if (!s) goto fail;
|
||||
|
||||
char device_path[260];
|
||||
strcpy_s(device_path, sizeof device_path, interface_detail[0].DevicePath);
|
||||
|
||||
if (resource != NULL) {
|
||||
strcat_s(device_path, 4, "\\");
|
||||
strcat_s(device_path, 4, resource);
|
||||
}
|
||||
|
||||
printf("Using device located at %s\n", device_path);
|
||||
HANDLE device =
|
||||
CreateFileA(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, NULL);
|
||||
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
return device;
|
||||
|
||||
fail:
|
||||
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
BOOL amEepromReadBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data) {
|
||||
mxsmbus_request_packet smbus_req = {
|
||||
.status = 0,
|
||||
.prt = 0x09,
|
||||
.addr = SMBUS_EEPROM,
|
||||
.reg = reg << 5,
|
||||
.dlen = len,
|
||||
.data = { 0 },
|
||||
};
|
||||
|
||||
DWORD _dummy;
|
||||
BOOL s = DeviceIoControl(mxsmbus, (DWORD)IOCTL_MXSMBUS_I2C, &smbus_req, sizeof smbus_req,
|
||||
&smbus_req, sizeof smbus_req, &_dummy, NULL);
|
||||
if (!s) return FALSE;
|
||||
if (smbus_req.status) return FALSE;
|
||||
memcpy(data, smbus_req.data, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL amEepromWriteBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data) {
|
||||
mxsmbus_request_packet smbus_req = {
|
||||
.status = 0,
|
||||
.prt = 0x08,
|
||||
.addr = SMBUS_EEPROM,
|
||||
.reg = reg << 5,
|
||||
.dlen = len,
|
||||
.data = { 0 },
|
||||
};
|
||||
memcpy(smbus_req.data, data, sizeof smbus_req.data);
|
||||
|
||||
DWORD _dummy;
|
||||
BOOL s = DeviceIoControl(mxsmbus, (DWORD)IOCTL_MXSMBUS_I2C, &smbus_req, sizeof smbus_req,
|
||||
&smbus_req, sizeof smbus_req, &_dummy, NULL);
|
||||
if (!s) return FALSE;
|
||||
if (smbus_req.status) return FALSE;
|
||||
memcpy(data, smbus_req.data, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void amEepromRepairChecksum(BYTE *data) {
|
||||
crc32_build_table();
|
||||
|
||||
DWORD check = crc32(28, data + 4, 0);
|
||||
((DWORD*)data)[0] = check;
|
||||
}
|
13
src/micetools/lib/am/amEeprom.h
Normal file
13
src/micetools/lib/am/amEeprom.h
Normal file
@ -0,0 +1,13 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../../dll/smbus.h"
|
||||
|
||||
DEFINE_GUID(MXSMBUS_GUID, 0x5C49E1FE, 0x3FEC, 0x4B8D, 0xA4, 0xB5, 0x76, 0xBE, 0x70, 0x25, 0xD8, 0x42);
|
||||
DEFINE_GUID(PLATFORM_GUID, 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3e, 0x30, 0x1F, 0x73);
|
||||
|
||||
HANDLE amEepromCreateDeviceFile(const GUID *guid, LPCSTR resource, DWORD member_index);
|
||||
|
||||
BOOL amEepromReadBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data);
|
||||
BOOL amEepromWriteBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data);
|
||||
|
||||
void amEepromRepairChecksum(BYTE* data);
|
@ -1,19 +1,19 @@
|
||||
#include <amtimer.h>
|
||||
|
||||
int frequency_loaded = 0;
|
||||
LARGE_INTEGER frequency;
|
||||
|
||||
amtime_t* amiTimerGet(amtime_t* time) {
|
||||
LARGE_INTEGER counter;
|
||||
|
||||
if (time == NULL) return NULL;
|
||||
|
||||
if (frequency_loaded == 0) {
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
frequency_loaded = 1;
|
||||
}
|
||||
QueryPerformanceCounter(&counter);
|
||||
time->microseconds = (counter.QuadPart * 1000000) / frequency.QuadPart;
|
||||
time->seconds = counter.QuadPart / frequency.QuadPart;
|
||||
return time;
|
||||
}
|
||||
#include <amTimer.h>
|
||||
|
||||
int frequency_loaded = 0;
|
||||
LARGE_INTEGER frequency;
|
||||
|
||||
amtime_t* amiTimerGet(amtime_t* time) {
|
||||
LARGE_INTEGER counter;
|
||||
|
||||
if (time == NULL) return NULL;
|
||||
|
||||
if (frequency_loaded == 0) {
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
frequency_loaded = 1;
|
||||
}
|
||||
QueryPerformanceCounter(&counter);
|
||||
time->microseconds = (unsigned int)((counter.QuadPart * 1000000) / frequency.QuadPart);
|
||||
time->seconds = (unsigned int)(counter.QuadPart / frequency.QuadPart);
|
||||
return time;
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
amlib = static_library(
|
||||
'am',
|
||||
sources: [
|
||||
'amtimer.c',
|
||||
],
|
||||
)
|
||||
amlib = static_library(
|
||||
'am',
|
||||
sources: [
|
||||
'amTimer.c',
|
||||
'amEeprom.c',
|
||||
],
|
||||
link_with: [
|
||||
mice_lib
|
||||
],
|
||||
)
|
||||
|
@ -1,111 +1,118 @@
|
||||
#include "dmi.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
LPBYTE dmi_table = NULL;
|
||||
WORD dmi_size = 0;
|
||||
size_t _dmi_max = 0;
|
||||
|
||||
DMI_BIOS deafult_dmi_bios = {
|
||||
.Head.Type = 0x00,
|
||||
.Head.Length = 0x12,
|
||||
.Head.Handle = 0x0000,
|
||||
.Vendor = 0x00,
|
||||
.Version = 0x00,
|
||||
.StartSegment = 0x0000,
|
||||
.ReleaseDate = 0x00,
|
||||
.ROMSize = 0x00,
|
||||
.Chars = 0x04,
|
||||
};
|
||||
|
||||
DMI_SYSTEM default_dmi_system = {
|
||||
.Head.Type = 0x01,
|
||||
.Head.Length = 0x08,
|
||||
.Head.Handle = 0x0001,
|
||||
// TODO: Are these used?
|
||||
.Manufacturer = 0x00,
|
||||
.ProductName = 0x00,
|
||||
.Version = 0x00,
|
||||
.Serial = 0x00,
|
||||
};
|
||||
|
||||
DMI_STRING deafult_dmi_string = {
|
||||
.Head.Type = 0x0b,
|
||||
.Head.Length = 0x05,
|
||||
.Head.Handle = 0x0002,
|
||||
.NoStrings = 0x00,
|
||||
};
|
||||
|
||||
static void dmi_init(void) {
|
||||
if (dmi_table) free(dmi_table);
|
||||
_dmi_max = 0xff;
|
||||
dmi_table = (LPBYTE)malloc(_dmi_max);
|
||||
memset(dmi_table, 0, _dmi_max);
|
||||
dmi_size = 0;
|
||||
}
|
||||
|
||||
static void dmi_append(void* data, size_t size) {
|
||||
if (!dmi_table) return;
|
||||
while (dmi_size + (size + 1) >= _dmi_max) {
|
||||
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
|
||||
if (!new_table) return;
|
||||
dmi_table = new_table;
|
||||
}
|
||||
memcpy(dmi_table + dmi_size, data, size);
|
||||
dmi_size += size;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
}
|
||||
|
||||
static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...) {
|
||||
va_list args;
|
||||
va_start(args, num_strings);
|
||||
|
||||
dmi_append(data, size);
|
||||
dmi_size -= 2;
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
char* str = va_arg(args, char*);
|
||||
int len = strlen(str);
|
||||
memcpy((char*)dmi_table + dmi_size, str, len + 1);
|
||||
dmi_size += len + 1;
|
||||
dmi_table[dmi_size - 1] = 0;
|
||||
}
|
||||
dmi_table[dmi_size++] = 0;
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dmi_build_default() {
|
||||
dmi_init();
|
||||
dmi_append(&deafult_dmi_bios, sizeof deafult_dmi_bios);
|
||||
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
|
||||
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
|
||||
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 1, "Supermicro");
|
||||
|
||||
deafult_dmi_string.NoStrings = 3;
|
||||
|
||||
dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string,
|
||||
// OEM strings:
|
||||
// 0: ??
|
||||
// 1: ??
|
||||
// 2: Platform ID (AAL, AAM)
|
||||
// AAL = Nvidia drivers
|
||||
// AAM = AMD drivers
|
||||
// *** = No dedicated drivers
|
||||
// 3: ??
|
||||
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
|
||||
// If present -> makes board = 4
|
||||
// AAL = 4
|
||||
// AAM = 4
|
||||
// Supermicro = 4
|
||||
// Advantech = 4
|
||||
5, ".", ".", "AAM", ".", "AAL");
|
||||
}
|
||||
|
||||
BYTE dmi_calc_checksum(const char* buf, int len) {
|
||||
int sum = 0;
|
||||
int a;
|
||||
for (a = 0; a < len; a++) sum += buf[a];
|
||||
return (BYTE)(sum == 0);
|
||||
#include "dmi.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
LPBYTE dmi_table = NULL;
|
||||
WORD dmi_size = 0;
|
||||
WORD _dmi_max = 0;
|
||||
|
||||
DMI_BIOS deafult_dmi_bios = {
|
||||
.Head.Type = 0x00,
|
||||
.Head.Length = 0x12,
|
||||
.Head.Handle = 0x0000,
|
||||
.Vendor = 0x01, // "American Megatrends Inc."
|
||||
.Version = 0x02, // "080015 "
|
||||
.StartSegment = 0x0000, // '00 f0'h
|
||||
.ReleaseDate = 0x03, // "07/28/2011"
|
||||
.ROMSize = 0x00, // 03h
|
||||
.Chars = 0x1f, // '1F 90 DA 8B'h
|
||||
.VerMajor = 0x08,
|
||||
.VerMinor = 0x0f,
|
||||
.ECVerMajor = 0xff,
|
||||
.ECVerMinor = 0xff,
|
||||
};
|
||||
|
||||
DMI_SYSTEM default_dmi_system = {
|
||||
.Head.Type = 0x01,
|
||||
.Head.Length = 0x08,
|
||||
.Head.Handle = 0x0001,
|
||||
.Manufacturer = 0x01, // "NEC"
|
||||
.ProductName = 0x02, // "To Be Filled By O.E.M."
|
||||
.Version = 0x03, // "To Be Filled By O.E.M."
|
||||
.Serial = 0x04, // "To Be Filled By O.E.M."
|
||||
};
|
||||
|
||||
DMI_STRING deafult_dmi_string = {
|
||||
.Head.Type = 0x0b,
|
||||
.Head.Length = 0x05,
|
||||
.Head.Handle = 0x0002,
|
||||
.NoStrings = 0x00,
|
||||
};
|
||||
|
||||
static void dmi_init(void) {
|
||||
if (dmi_table) free(dmi_table);
|
||||
_dmi_max = 0xff;
|
||||
dmi_table = (LPBYTE)malloc(_dmi_max);
|
||||
memset(dmi_table, 0, _dmi_max);
|
||||
dmi_size = 0;
|
||||
}
|
||||
|
||||
static void dmi_append(void* data, WORD size) {
|
||||
if (!dmi_table) return;
|
||||
while (dmi_size + (size + 1) >= _dmi_max) {
|
||||
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
|
||||
if (!new_table) return;
|
||||
dmi_table = new_table;
|
||||
}
|
||||
memcpy(dmi_table + dmi_size, data, size);
|
||||
dmi_size += size;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
}
|
||||
|
||||
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...) {
|
||||
va_list args;
|
||||
va_start(args, num_strings);
|
||||
|
||||
dmi_append(data, size);
|
||||
dmi_size -= 2;
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
char* str = va_arg(args, char*);
|
||||
WORD len = strlen(str) & 0xffff;
|
||||
memcpy((char*)dmi_table + dmi_size, str, len + 1);
|
||||
dmi_size += len + 1;
|
||||
dmi_table[dmi_size - 1] = 0;
|
||||
}
|
||||
dmi_table[dmi_size++] = 0;
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dmi_build_default() {
|
||||
dmi_init();
|
||||
dmi_append_with_strings(&deafult_dmi_bios, sizeof deafult_dmi_bios, 3,
|
||||
"American Megatrends Inc.", "080015 ", "07/28/2011");
|
||||
|
||||
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
|
||||
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4, "NEC",
|
||||
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.",
|
||||
"To Be Filled By O.E.M.");
|
||||
|
||||
deafult_dmi_string.NoStrings = 5;
|
||||
|
||||
dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string,
|
||||
// OEM strings:
|
||||
// 0: ??
|
||||
// 1: ??
|
||||
// 2: Platform ID (AAL, AAM)
|
||||
// AAL = Nvidia drivers
|
||||
// AAM = AMD drivers
|
||||
// *** = No dedicated drivers
|
||||
// 3: ??
|
||||
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
|
||||
// If present -> makes board = 4
|
||||
// AAL = 4
|
||||
// AAM = 4
|
||||
// Supermicro = 4
|
||||
// Advantech = 4
|
||||
// These values are pulled from an 846-5004D
|
||||
5, "DAC-BJ02", "DAC-BJ02", "AAL", "Advantech", "AAL2");
|
||||
}
|
||||
|
||||
BYTE dmi_calc_checksum(const char* buf, int len) {
|
||||
int sum = 0;
|
||||
int a;
|
||||
for (a = 0; a < len; a++) sum += buf[a];
|
||||
return (BYTE)(sum == 0);
|
||||
}
|
@ -1,58 +1,62 @@
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern LPBYTE dmi_table;
|
||||
extern WORD dmi_size;
|
||||
|
||||
// #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
BYTE Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
} DMI_SECTION_HEADER;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
CHAR Signature[5];
|
||||
BYTE Checksum;
|
||||
WORD StructLength;
|
||||
DWORD StructAddr;
|
||||
WORD NumberOfStructs;
|
||||
BYTE BCDRevision;
|
||||
BYTE Reserved;
|
||||
} DMI_HEADER;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Vendor;
|
||||
BYTE Version;
|
||||
WORD StartSegment;
|
||||
BYTE ReleaseDate;
|
||||
BYTE ROMSize;
|
||||
uint64_t Chars;
|
||||
} DMI_BIOS;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Manufacturer;
|
||||
BYTE ProductName;
|
||||
BYTE Version;
|
||||
BYTE Serial;
|
||||
} DMI_SYSTEM;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE NoStrings;
|
||||
} DMI_STRING;
|
||||
|
||||
static void dmi_init(void);
|
||||
static void dmi_append(void* data, size_t size);
|
||||
static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...);
|
||||
|
||||
void dmi_build_default(void);
|
||||
BYTE dmi_calc_checksum(const char* buf, int len);
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern LPBYTE dmi_table;
|
||||
extern WORD dmi_size;
|
||||
|
||||
// #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
BYTE Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
} DMI_SECTION_HEADER;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
CHAR Signature[5];
|
||||
BYTE Checksum;
|
||||
WORD StructLength;
|
||||
DWORD StructAddr;
|
||||
WORD NumberOfStructs;
|
||||
BYTE BCDRevision;
|
||||
BYTE Reserved;
|
||||
} DMI_HEADER;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Vendor;
|
||||
BYTE Version;
|
||||
WORD StartSegment;
|
||||
BYTE ReleaseDate;
|
||||
BYTE ROMSize;
|
||||
uint64_t Chars;
|
||||
BYTE VerMajor;
|
||||
BYTE VerMinor;
|
||||
BYTE ECVerMajor;
|
||||
BYTE ECVerMinor;
|
||||
} DMI_BIOS;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE Manufacturer;
|
||||
BYTE ProductName;
|
||||
BYTE Version;
|
||||
BYTE Serial;
|
||||
} DMI_SYSTEM;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
DMI_SECTION_HEADER Head;
|
||||
BYTE NoStrings;
|
||||
} DMI_STRING;
|
||||
|
||||
static void dmi_init(void);
|
||||
static void dmi_append(void* data, WORD size);
|
||||
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...);
|
||||
|
||||
void dmi_build_default(void);
|
||||
BYTE dmi_calc_checksum(const char* buf, int len);
|
||||
|
File diff suppressed because it is too large
Load Diff
1
src/micetools/lib/libpcp/libpcp.c
Normal file
1
src/micetools/lib/libpcp/libpcp.c
Normal file
@ -0,0 +1 @@
|
||||
#include "libpcp.h"
|
@ -1,23 +1,23 @@
|
||||
compiler = meson.get_compiler('c')
|
||||
ws2 = compiler.find_library('ws2_32', required: true)
|
||||
|
||||
sources = [
|
||||
'libpcp.c',
|
||||
'pcpt.c',
|
||||
'pcpp.c',
|
||||
'pcpa.c',
|
||||
'pcp.c',
|
||||
'util.c',
|
||||
]
|
||||
|
||||
libpcp = static_library(
|
||||
'pcp',
|
||||
name_suffix: 'lib',
|
||||
sources: sources,
|
||||
dependencies: [
|
||||
ws2,
|
||||
],
|
||||
link_with: [
|
||||
amlib,
|
||||
],
|
||||
)
|
||||
compiler = meson.get_compiler('c')
|
||||
ws2 = compiler.find_library('ws2_32', required: true)
|
||||
|
||||
sources = [
|
||||
'libpcp.c',
|
||||
'pcpt.c',
|
||||
'pcpp.c',
|
||||
'pcpa.c',
|
||||
'pcp.c',
|
||||
'util.c',
|
||||
]
|
||||
|
||||
libpcp = static_library(
|
||||
'pcp',
|
||||
name_suffix: 'lib',
|
||||
sources: sources,
|
||||
dependencies: [
|
||||
ws2,
|
||||
],
|
||||
link_with: [
|
||||
amlib,
|
||||
],
|
||||
)
|
||||
|
3
src/micetools/lib/libpcp/pcp.c
Normal file
3
src/micetools/lib/libpcp/pcp.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include "pcp.h"
|
||||
|
||||
char* LIBPCP_VERSION = "\nlibpcp Ver.1.08 Build:Aug 12 2012 00:13:32 (micetools bootleg)\n";
|
@ -1,71 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#define PCP_LOG(fmt, ...) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__)
|
||||
#define ZERO(x) memset(&(x), 0, sizeof(x))
|
||||
#define ZERO_BUF(x) memset((x), 0, sizeof(*x))
|
||||
|
||||
#include <Winsock2.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../am/amtimer.h"
|
||||
|
||||
#define PCP_CHAR_PROMPT '>'
|
||||
#define PCP_CHAR_BINACK '$'
|
||||
#define PCP_CHAR_HASH '#'
|
||||
#define PCP_CHAR_UNKNOWN '?'
|
||||
#define PCP_CHAR_SEP '&'
|
||||
#define PCP_CHAR_EQU '='
|
||||
#define PCP_CHAR_CR '\r'
|
||||
#define PCP_CHAR_LF '\n'
|
||||
#define PCP_CHAR_EOF '\0'
|
||||
#define PCP_WHITESPACE(x) ((x) == ' ' || (x) == '\t')
|
||||
|
||||
extern char* LIBPCP_VERSION;
|
||||
|
||||
typedef unsigned int undefined4;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef int timeout_t;
|
||||
|
||||
#define PCP_BUF_MAX 256
|
||||
#define PCP_CMDS_MAX 64
|
||||
#define PCP_KEYWORD_MAX 32
|
||||
#define PCP_SEND_BUF_MAX 8
|
||||
|
||||
typedef struct pcp_parse_data {
|
||||
char strings[PCP_BUF_MAX];
|
||||
byte keywords[PCP_CMDS_MAX];
|
||||
byte values[PCP_CMDS_MAX];
|
||||
uint cmd_count;
|
||||
} pcp_parse_data_t;
|
||||
typedef struct pcp_send_data {
|
||||
char data[PCP_BUF_MAX];
|
||||
size_t length;
|
||||
} pcp_send_data_t;
|
||||
|
||||
// Errors
|
||||
#define OPEN_MODE_GLOBAL 0
|
||||
#define OPEN_MODE_1 1
|
||||
// #define OPEN_MODE_2 2
|
||||
|
||||
typedef enum binary_mode {
|
||||
binary_mode_none = 0,
|
||||
binary_mode_send = 1,
|
||||
binary_mode_recv = 2,
|
||||
} binary_mode_t;
|
||||
|
||||
#define PCPT_CONFIG_0 0
|
||||
#define PCPT_CONFIG_1 1
|
||||
#define PCPT_SO_LINGER 2
|
||||
#define PCPT_TCP_NODELAY 3
|
||||
|
||||
#define HANDLE_INVAL -1
|
||||
#define TIMEOUT_NONE -1
|
||||
|
||||
#define PCPT_CLOSED 0
|
||||
#define PCPT_LISTENING 1
|
||||
#define PCPT_CONNECTED 2
|
||||
#pragma once
|
||||
|
||||
#define PCP_LOG(fmt, ...) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__)
|
||||
#define ZERO(x) memset(&(x), 0, sizeof(x))
|
||||
#define ZERO_BUF(x) memset((x), 0, sizeof(*x))
|
||||
|
||||
#include <Winsock2.h>
|
||||
#include <ws2ipdef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../am/amtimer.h"
|
||||
|
||||
#define PCP_CHAR_PROMPT '>'
|
||||
#define PCP_CHAR_BINACK '$'
|
||||
#define PCP_CHAR_HASH '#'
|
||||
#define PCP_CHAR_UNKNOWN '?'
|
||||
#define PCP_CHAR_SEP '&'
|
||||
#define PCP_CHAR_EQU '='
|
||||
#define PCP_CHAR_CR '\r'
|
||||
#define PCP_CHAR_LF '\n'
|
||||
#define PCP_CHAR_EOF '\0'
|
||||
#define PCP_WHITESPACE(x) ((x) == ' ' || (x) == '\t')
|
||||
|
||||
extern char* LIBPCP_VERSION;
|
||||
|
||||
typedef unsigned int undefined4;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef unsigned int timeout_t;
|
||||
|
||||
#define PCP_BUF_MAX 256
|
||||
#define PCP_CMDS_MAX 64
|
||||
#define PCP_KEYWORD_MAX 32
|
||||
#define PCP_SEND_BUF_MAX 8
|
||||
|
||||
typedef struct pcp_parse_data {
|
||||
char strings[PCP_BUF_MAX];
|
||||
byte keywords[PCP_CMDS_MAX];
|
||||
byte values[PCP_CMDS_MAX];
|
||||
uint cmd_count;
|
||||
} pcp_parse_data_t;
|
||||
typedef struct pcp_send_data {
|
||||
unsigned char data[PCP_BUF_MAX];
|
||||
size_t length;
|
||||
} pcp_send_data_t;
|
||||
|
||||
// Errors
|
||||
#define OPEN_MODE_GLOBAL 0
|
||||
#define OPEN_MODE_1 1
|
||||
// #define OPEN_MODE_2 2
|
||||
|
||||
typedef enum binary_mode {
|
||||
binary_mode_none = 0,
|
||||
binary_mode_send = 1,
|
||||
binary_mode_recv = 2,
|
||||
} binary_mode_t;
|
||||
|
||||
#define PCPT_CONFIG_0 0
|
||||
#define PCPT_CONFIG_1 1
|
||||
#define PCPT_SO_LINGER 2
|
||||
#define PCPT_TCP_NODELAY 3
|
||||
|
||||
#define SOCKET_INVAL ((SOCKET)-1)
|
||||
#define HANDLE_INVAL -1
|
||||
#define TIMEOUT_NONE ((DWORD)-1)
|
||||
|
||||
#define PCPT_CLOSED 0
|
||||
#define PCPT_LISTENING 1
|
||||
#define PCPT_CONNECTED 2
|
||||
|
630
src/micetools/lib/libpcp/pcpa.c
Normal file
630
src/micetools/lib/libpcp/pcpa.c
Normal file
@ -0,0 +1,630 @@
|
||||
#include "pcpa.h"
|
||||
|
||||
e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err) {
|
||||
switch (err) {
|
||||
case e_pcpp_ok:
|
||||
return e_pcpa_ok;
|
||||
case e_pcpp_to:
|
||||
return e_pcpa_to;
|
||||
case e_pcpp_closed:
|
||||
return e_pcpa_closed;
|
||||
case e_pcpp_no_client:
|
||||
return e_pcpa_no_client;
|
||||
case e_pcpp_wsa_noinit:
|
||||
return e_pcpa_wsa_noinit;
|
||||
case e_pcpp_inval_addr:
|
||||
return e_pcpa_inval_addr;
|
||||
case -14:
|
||||
return (e_pcpa_t)-16;
|
||||
case -13:
|
||||
return (e_pcpa_t)-15;
|
||||
case e_pcpp_timeout_open:
|
||||
return e_pcpa_timeout_open;
|
||||
case -11:
|
||||
return (e_pcpa_t)-13;
|
||||
case e_pcpp_recv_unset:
|
||||
return e_pcpa_cb_table_full;
|
||||
case -9:
|
||||
return (e_pcpa_t)-7;
|
||||
case -8:
|
||||
return (e_pcpa_t)-6;
|
||||
case -7:
|
||||
return (e_pcpa_t)-3;
|
||||
case e_pcpp_timeout_closed:
|
||||
return e_pcpa_timeout_closed;
|
||||
case e_pcpp_param_invalid:
|
||||
return e_pcpa_param_invalid;
|
||||
case -4:
|
||||
return (e_pcpa_t)-8;
|
||||
case e_pcpp_already_open:
|
||||
return e_pcpa_already_open;
|
||||
case e_pcpp_cannot_open:
|
||||
return e_pcpa_cannot_open;
|
||||
case e_pcpp_not_open:
|
||||
return e_pcpa_not_open;
|
||||
default:
|
||||
return e_pcpa_closed;
|
||||
}
|
||||
}
|
||||
|
||||
void pcpaCloseBinary(pcpa_t *stream) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn't set\n");
|
||||
return;
|
||||
}
|
||||
stream->binary_mode = binary_mode_none;
|
||||
|
||||
pcppCloseBinary(&stream->pcpp);
|
||||
}
|
||||
|
||||
void pcpaClose(pcpa_t *stream) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return;
|
||||
}
|
||||
pcppClose(&stream->pcpp);
|
||||
stream->err = e_pcpa_unknown;
|
||||
stream->state = 0;
|
||||
stream->callback_table = NULL;
|
||||
stream->callback_max = 0;
|
||||
stream->callback_count = 0;
|
||||
stream->recv_buffer = NULL;
|
||||
stream->recv_buffer_len = 0;
|
||||
stream->send_buffer = NULL;
|
||||
stream->send_buffer_len = 0;
|
||||
stream->binary_mode = binary_mode_none;
|
||||
stream->binary_mode_before_cb = NULL;
|
||||
stream->binary_mode_after_cb = NULL;
|
||||
stream->binary_mode_before_data = NULL;
|
||||
stream->binary_mode_after_data = NULL;
|
||||
memset(&stream->send_data, 0, sizeof stream->send_data);
|
||||
(stream->send_data).length = 0;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaInitStream(pcpa_t *stream) {
|
||||
if (LIBPCP_VERSION == NULL) {
|
||||
PCP_LOG("error PCPA version isn\'t set\n");
|
||||
return e_pcpa_generic;
|
||||
}
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
|
||||
e_pcpp_t err = pcppInitStream(&stream->pcpp);
|
||||
if (err != e_pcpp_ok) {
|
||||
return err == e_pcpp_wsa_noinit ? e_pcpa_wsa_noinit : e_pcpa_param_invalid;
|
||||
}
|
||||
|
||||
stream->err = e_pcpa_unknown;
|
||||
stream->state = 0;
|
||||
stream->callback_table = NULL;
|
||||
stream->callback_max = 0;
|
||||
stream->callback_count = 0;
|
||||
stream->recv_buffer = NULL;
|
||||
stream->recv_buffer_len = 0;
|
||||
stream->send_buffer = NULL;
|
||||
stream->send_buffer_len = 0;
|
||||
stream->binary_mode = binary_mode_none;
|
||||
stream->binary_mode_before_cb = NULL;
|
||||
stream->binary_mode_after_cb = NULL;
|
||||
stream->binary_mode_before_data = NULL;
|
||||
stream->binary_mode_after_data = NULL;
|
||||
ZERO(stream->recv_data);
|
||||
ZERO(stream->send_data);
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaOpenServerWithBinary(pcpa_t *stream, int open_mode, u_short port, u_short binary_port,
|
||||
undefined4 param_5) {
|
||||
e_pcpa_t err;
|
||||
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
|
||||
switch (open_mode) {
|
||||
case 0:
|
||||
stream->err = err = _errP2A(pcppOpenServer(&stream->pcpp, 0, port, param_5));
|
||||
if (err != e_pcpa_ok) {
|
||||
PCP_LOG("error pcppOpenServer\n");
|
||||
return err;
|
||||
}
|
||||
stream->err = err = _errP2A(pcppOpenBinaryServer(&stream->pcpp, 0, binary_port));
|
||||
if (err != e_pcpa_ok) {
|
||||
PCP_LOG("error pcppOpenBinaryServer\n");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
stream->err = err = _errP2A(pcppOpenServer(&stream->pcpp, 1, port, param_5));
|
||||
if (err != e_pcpa_ok) {
|
||||
PCP_LOG("error pcppOpenServer\n");
|
||||
return err;
|
||||
}
|
||||
stream->err = err = _errP2A(pcppOpenBinaryServer(&stream->pcpp, 1, binary_port));
|
||||
if (err != e_pcpa_ok) {
|
||||
PCP_LOG("error pcppOpenBinaryServer\n");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PCP_LOG("error Open Mode isn\'t set\n");
|
||||
return stream->err = e_pcpa_generic;
|
||||
}
|
||||
|
||||
stream->state = 0;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetCallbackFunc(pcpa_t *stream, char *keyword, pcpa_callback *callback, void *data) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
|
||||
if (keyword == NULL) {
|
||||
PCP_LOG("error keyword isn\'t set\n");
|
||||
return e_pcpa_generic;
|
||||
}
|
||||
|
||||
if (callback == NULL) {
|
||||
PCP_LOG("error Callback func isn\'t set\n");
|
||||
return e_pcpa_generic;
|
||||
}
|
||||
|
||||
if (stream->callback_table == NULL) {
|
||||
PCP_LOG("error Callback_table buffer isn\'t set\n");
|
||||
return e_pcpa_cb_table_unset;
|
||||
}
|
||||
|
||||
if (strnlen(keyword, PCP_KEYWORD_MAX + 1) > PCP_KEYWORD_MAX) {
|
||||
PCP_LOG("error a keyword is too long\n");
|
||||
return e_pcpa_generic;
|
||||
}
|
||||
|
||||
if (stream->callback_count >= stream->callback_max) return e_pcpa_cb_table_full;
|
||||
|
||||
sprintf_s(stream->callback_table[stream->callback_count].keyword, PCP_KEYWORD_MAX, "%s", keyword);
|
||||
stream->callback_table[stream->callback_count].callback = callback;
|
||||
stream->callback_table[stream->callback_count].data = data;
|
||||
stream->callback_count++;
|
||||
|
||||
return stream->err = e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t *stream, pcpa_cb_table_t *callback_table, uint callbacks_max) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
|
||||
if (callback_table == NULL || callbacks_max == 0) return e_pcpa_timeout_closed;
|
||||
|
||||
stream->callback_max = callbacks_max;
|
||||
stream->callback_table = callback_table;
|
||||
stream->callback_count = 0;
|
||||
stream->err = e_pcpa_ok;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
pcp_send_data_t *pcpaSetSendPacket(pcpa_t *stream, char *keyword, char *value) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return NULL;
|
||||
}
|
||||
return pcppSetSendPacket(&stream->send_data, keyword, value);
|
||||
}
|
||||
|
||||
char *pcpaGetCommand(pcpa_t *pcpa, char *command) {
|
||||
if (pcpa == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pcppGetCommand(&pcpa->recv_data, command);
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) {
|
||||
byte bVar1;
|
||||
pcpa_callback *callback;
|
||||
char *pbVar3;
|
||||
int iVar3;
|
||||
e_pcpa_t eVar4;
|
||||
char *pbVar4;
|
||||
uint ms;
|
||||
e_pcpp_t iVar5;
|
||||
bool bVar6;
|
||||
uint local_14;
|
||||
amtime_t time;
|
||||
amtime_t time_start;
|
||||
int timeout;
|
||||
|
||||
local_14 = timeout_ms;
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
amiTimerGet(&time_start);
|
||||
timeout = timeout_ms;
|
||||
do {
|
||||
ms = 0;
|
||||
switch (stream->state) {
|
||||
case 0:
|
||||
amiTimerGet(&time);
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
if (timeout_ms != -1) {
|
||||
if (ms < (uint)timeout_ms) {
|
||||
timeout = timeout_ms - ms;
|
||||
local_14 = timeout;
|
||||
} else {
|
||||
timeout = 0;
|
||||
local_14 = timeout;
|
||||
}
|
||||
}
|
||||
stream->state = 3;
|
||||
iVar5 = pcppRecvRequest(&stream->pcpp, &stream->recv_data, timeout);
|
||||
eVar4 = _errP2A(iVar5);
|
||||
stream->err = eVar4;
|
||||
timeout = local_14;
|
||||
if (eVar4 != e_pcpa_to) {
|
||||
if (eVar4 == e_pcpa_ok) {
|
||||
stream->state = 10;
|
||||
amiTimerGet(&time);
|
||||
if (timeout_ms != -1) {
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
goto joined_r0x00454a58;
|
||||
}
|
||||
} else {
|
||||
stream->state = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
stream->err = e_pcpa_unknown;
|
||||
goto LAB_00454d84;
|
||||
case 3:
|
||||
case 4:
|
||||
case 9:
|
||||
amiTimerGet(&time);
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
if (timeout_ms != -1) {
|
||||
if (ms < (uint)timeout_ms) {
|
||||
timeout = timeout_ms - ms;
|
||||
local_14 = timeout;
|
||||
} else {
|
||||
timeout = 0;
|
||||
local_14 = timeout;
|
||||
}
|
||||
}
|
||||
iVar5 = pcppIsBusy(&stream->pcpp, timeout);
|
||||
eVar4 = _errP2A(iVar5);
|
||||
stream->err = eVar4;
|
||||
timeout = local_14;
|
||||
if (eVar4 != e_pcpa_to) {
|
||||
if (stream->state == 4) {
|
||||
memset(&stream->send_data, 0, PCP_BUF_MAX);
|
||||
(stream->send_data).length = 0;
|
||||
}
|
||||
if (stream->err == e_pcpa_ok) {
|
||||
if (stream->binary_mode == binary_mode_none) {
|
||||
stream->state = (stream->state != 3) - 1 & 10;
|
||||
amiTimerGet(&time);
|
||||
if (timeout_ms != -1) {
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
joined_r0x00454a58:
|
||||
if ((uint)timeout_ms <= ms) {
|
||||
stream->err = e_pcpa_to;
|
||||
return stream->err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pcpaCloseBinary(stream);
|
||||
stream->state = 0;
|
||||
stream->binary_mode = binary_mode_none;
|
||||
if (stream->binary_mode_after_cb != NULL) {
|
||||
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
|
||||
stream->binary_mode_after_cb = NULL;
|
||||
}
|
||||
amiTimerGet(&time);
|
||||
if (timeout_ms != -1) {
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
goto joined_r0x00454a58;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((stream->state == 9) && (stream->binary_mode != binary_mode_none)) {
|
||||
pcpaCloseBinary(stream);
|
||||
if (stream->binary_mode_after_cb != NULL) {
|
||||
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
|
||||
stream->binary_mode_after_cb = NULL;
|
||||
}
|
||||
stream->binary_mode = binary_mode_none;
|
||||
}
|
||||
stream->state = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
callback = stream->binary_mode_before_cb;
|
||||
(stream->pcpp).last_active = _amTimeMs(time_start);
|
||||
if (callback != NULL) {
|
||||
(*callback)(stream, stream->binary_mode_before_data);
|
||||
stream->binary_mode_before_cb = NULL;
|
||||
}
|
||||
amiTimerGet(&time);
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
if (timeout_ms != -1) {
|
||||
if (ms < (uint)timeout_ms) {
|
||||
timeout = timeout_ms - ms;
|
||||
local_14 = timeout;
|
||||
} else {
|
||||
timeout = 0;
|
||||
local_14 = timeout;
|
||||
}
|
||||
}
|
||||
eVar4 = pcpaSendBinary(stream, timeout);
|
||||
stream->err = eVar4;
|
||||
if (eVar4 == e_pcpa_to) {
|
||||
stream->state = 9;
|
||||
} else {
|
||||
pcpaCloseBinary(stream);
|
||||
if (stream->binary_mode_after_cb != NULL) {
|
||||
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
|
||||
stream->binary_mode_after_cb = NULL;
|
||||
}
|
||||
stream->binary_mode = binary_mode_none;
|
||||
stream->state = 0;
|
||||
if (stream->err == e_pcpa_ok) {
|
||||
LAB_00454a1a:
|
||||
amiTimerGet(&time);
|
||||
if (timeout_ms != -1) {
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
goto joined_r0x00454a58;
|
||||
}
|
||||
} else {
|
||||
PCP_LOG("error pcpaSendBinary\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
callback = stream->binary_mode_before_cb;
|
||||
(stream->pcpp).last_active = _amTimeMs(time_start);
|
||||
if (callback != NULL) {
|
||||
(*callback)(stream, stream->binary_mode_before_data);
|
||||
stream->binary_mode_before_cb = NULL;
|
||||
}
|
||||
amiTimerGet(&time);
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
if (timeout_ms != -1) {
|
||||
if (ms < (uint)timeout_ms) {
|
||||
timeout = timeout_ms - ms;
|
||||
local_14 = timeout;
|
||||
} else {
|
||||
timeout = 0;
|
||||
local_14 = timeout;
|
||||
}
|
||||
}
|
||||
eVar4 = pcpaRecvBinary(stream, timeout);
|
||||
stream->err = eVar4;
|
||||
if (eVar4 == e_pcpa_to) {
|
||||
stream->state = 9;
|
||||
} else {
|
||||
pcpaCloseBinary(stream);
|
||||
if (stream->binary_mode_after_cb != NULL) {
|
||||
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
|
||||
stream->binary_mode_after_cb = NULL;
|
||||
}
|
||||
stream->binary_mode = binary_mode_none;
|
||||
stream->state = 0;
|
||||
if (stream->err == e_pcpa_ok) goto LAB_00454a1a;
|
||||
PCP_LOG("error pcpaRecvBinary\n");
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (stream->before_cb != NULL) {
|
||||
stream->before_cb(stream, stream->pcpp.sock.recv_buf);
|
||||
}
|
||||
|
||||
if (stream->callback_table == NULL) {
|
||||
PCP_LOG("error Callback_table buffer isn\'t set\n");
|
||||
|
||||
stream->err = e_pcpa_cb_table_unset;
|
||||
return stream->err;
|
||||
}
|
||||
if (stream->callback_count != 0) {
|
||||
iVar5 = 0;
|
||||
do {
|
||||
pbVar3 = pcppGetKeyword(&stream->recv_data, 0);
|
||||
pbVar4 = stream->callback_table->keyword + iVar5;
|
||||
do {
|
||||
bVar1 = *pbVar3;
|
||||
bVar6 = bVar1 < (byte)*pbVar4;
|
||||
if (bVar1 != *pbVar4) {
|
||||
LAB_004547c8:
|
||||
iVar3 = (1 - (uint)bVar6) - (uint)(bVar6 != 0);
|
||||
goto LAB_004547cd;
|
||||
}
|
||||
if (bVar1 == 0) break;
|
||||
bVar1 = ((byte *)pbVar3)[1];
|
||||
bVar6 = bVar1 < ((byte *)pbVar4)[1];
|
||||
if (bVar1 != ((byte *)pbVar4)[1]) goto LAB_004547c8;
|
||||
pbVar3 = (char *)((byte *)pbVar3 + 2);
|
||||
pbVar4 = (char *)((byte *)pbVar4 + 2);
|
||||
} while (bVar1 != 0);
|
||||
iVar3 = 0;
|
||||
LAB_004547cd:
|
||||
if (iVar3 == 0) {
|
||||
(stream->callback_table[ms].callback)(stream, stream->callback_table[ms].data);
|
||||
goto LAB_004547f1;
|
||||
}
|
||||
ms = ms + 1;
|
||||
iVar5 = iVar5 + 40;
|
||||
} while (ms < stream->callback_count);
|
||||
}
|
||||
pcppSetSendPacket(&stream->send_data, "?", 0);
|
||||
LAB_004547f1:
|
||||
amiTimerGet(&time);
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
if (timeout_ms != -1) {
|
||||
if (ms < (uint)timeout_ms) {
|
||||
local_14 = timeout_ms - ms;
|
||||
} else {
|
||||
local_14 = 0;
|
||||
}
|
||||
}
|
||||
iVar5 = pcppSendResponseTable(&stream->pcpp, &stream->send_data, local_14);
|
||||
eVar4 = _errP2A(iVar5);
|
||||
stream->err = eVar4;
|
||||
if (eVar4 == e_pcpa_to) {
|
||||
stream->state = 4;
|
||||
} else {
|
||||
memset(&stream->send_data, 0, PCP_BUF_MAX);
|
||||
(stream->send_data).length = 0;
|
||||
stream->state = 0;
|
||||
}
|
||||
if (stream->binary_mode != binary_mode_none) {
|
||||
stream->state = (stream->binary_mode == binary_mode_send) ? 7 : 8;
|
||||
}
|
||||
amiTimerGet(&time);
|
||||
timeout = local_14;
|
||||
if (timeout_ms != TIMEOUT_NONE) {
|
||||
ms = _amTimeDelta(time, time_start);
|
||||
goto joined_r0x00454a58;
|
||||
}
|
||||
}
|
||||
} while (stream->err == e_pcpa_ok);
|
||||
LAB_00454d84:
|
||||
return stream->err;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaRecvBinary(pcpa_t *stream, uint something) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (stream->recv_buffer == NULL) {
|
||||
PCP_LOG("error Recv buffer isn\'t set\n");
|
||||
pcpaCloseBinary(stream);
|
||||
pcpaClose(stream);
|
||||
return stream->err = e_pcpa_cb_table_full;
|
||||
}
|
||||
|
||||
stream->state = 8;
|
||||
e_pcpa_t err;
|
||||
stream->err = err = _errP2A(pcppRecvBinary(&stream->pcpp, stream->recv_buffer, stream->recv_buffer_len, something));
|
||||
if (err != e_pcpa_to) stream->state = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSendBinary(pcpa_t *stream, uint param_2) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (stream->send_buffer == NULL) {
|
||||
PCP_LOG("error Send buffer isn\'t set\n");
|
||||
stream->err = e_pcpa_cb_table_full;
|
||||
pcpaCloseBinary(stream);
|
||||
pcpaClose(stream);
|
||||
return stream->err;
|
||||
}
|
||||
|
||||
stream->state = 7;
|
||||
e_pcpa_t err;
|
||||
stream->err = err = _errP2A(pcppSendBinary(&stream->pcpp, stream->send_buffer, stream->send_buffer_len, param_2));
|
||||
if (err != e_pcpa_to) stream->state = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t *stream, byte *send_buffer, size_t len) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (send_buffer == NULL) {
|
||||
PCP_LOG("error Send Buffer isn\'t set\n");
|
||||
return e_pcpa_timeout_closed;
|
||||
}
|
||||
stream->send_buffer = send_buffer;
|
||||
stream->send_buffer_len = len;
|
||||
stream->err = e_pcpa_ok;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t *stream, pcpa_callback *callback, void *data) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error don\'t set stream\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (callback == NULL) {
|
||||
PCP_LOG("error Binary mode callback func isn\'t set\n");
|
||||
return e_pcpa_generic;
|
||||
}
|
||||
stream->binary_mode_before_cb = callback;
|
||||
stream->binary_mode_before_data = data;
|
||||
stream->err = e_pcpa_ok;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetAfterBinaryModeCallBackFunc(pcpa_t *stream, pcpa_callback *callback, void *data) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error don\'t set stream\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (callback == NULL) {
|
||||
PCP_LOG("error Binary mode callback func isn\'t set\n");
|
||||
return e_pcpa_generic;
|
||||
}
|
||||
stream->binary_mode_after_cb = callback;
|
||||
stream->binary_mode_after_data = data;
|
||||
stream->err = e_pcpa_ok;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetBinaryMode(pcpa_t *stream, binary_mode_t binary_mode) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (pcppGetServerSocket(&stream->pcpp, 1) == HANDLE_INVAL) {
|
||||
return stream->err = -19;
|
||||
}
|
||||
stream->binary_mode = binary_mode;
|
||||
stream->err = e_pcpa_ok;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t *stream, byte *recv_buffer, size_t len) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return e_pcpa_stream_unset;
|
||||
}
|
||||
if (recv_buffer == NULL) {
|
||||
PCP_LOG("error Recv Buffer isn\'t set\n");
|
||||
return e_pcpa_timeout_closed;
|
||||
}
|
||||
stream->recv_buffer = recv_buffer;
|
||||
stream->recv_buffer_len = len;
|
||||
stream->err = e_pcpa_ok;
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return NULL;
|
||||
}
|
||||
return pcppAddSendPacket(&stream->send_data, keyword, value);
|
||||
}
|
||||
|
||||
char *pcpaGetKeyword(pcpa_t *stream, uint keyword_num) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCPA stream isn\'t set\n");
|
||||
return NULL;
|
||||
}
|
||||
return pcppGetKeyword(&stream->recv_data, keyword_num);
|
||||
}
|
@ -1,76 +1,76 @@
|
||||
#include "pcpp.h"
|
||||
|
||||
typedef enum e_pcpa {
|
||||
e_pcpa_ok = 0,
|
||||
e_pcpa_to = 1,
|
||||
e_pcpa_closed = 2,
|
||||
e_pcpa_no_client = 3,
|
||||
e_pcpa_not_open = -1,
|
||||
e_pcpa_cannot_open = -2,
|
||||
e_pcpa_generic = -3,
|
||||
e_pcpa_param_invalid = -4,
|
||||
e_pcpa_timeout_closed = -5, // TODO: This is wrong (see: pcpaSetCallbackFuncBuffer)
|
||||
e_pcpa_cb_table_full = -9,
|
||||
e_pcpa_stream_unset = -10,
|
||||
e_pcpa_cb_table_unset = -11,
|
||||
e_pcpa_timeout_open = -14,
|
||||
e_pcpa_inval_addr = -17,
|
||||
e_pcpa_already_open = -18,
|
||||
e_pcpa_wsa_noinit = -20,
|
||||
e_pcpa_unknown = -21,
|
||||
} e_pcpa_t;
|
||||
|
||||
e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err);
|
||||
#define _errP2A(err) _pcpaGetErrorFromPcpp(err)
|
||||
|
||||
struct pcpa;
|
||||
typedef void(pcpa_callback)(struct pcpa* stream, void* data);
|
||||
|
||||
typedef struct pcpa_cb_table {
|
||||
char keyword[PCP_KEYWORD_MAX];
|
||||
void* data;
|
||||
pcpa_callback* callback;
|
||||
} pcpa_cb_table_t;
|
||||
|
||||
typedef struct pcpa {
|
||||
pcpp_t pcpp;
|
||||
e_pcpa_t err;
|
||||
uint state;
|
||||
pcpa_cb_table_t* callback_table;
|
||||
uint callback_max;
|
||||
uint callback_count;
|
||||
char* recv_buffer;
|
||||
size_t recv_buffer_len;
|
||||
char* send_buffer;
|
||||
size_t send_buffer_len;
|
||||
binary_mode_t binary_mode;
|
||||
pcpa_callback* binary_mode_before_cb;
|
||||
void* binary_mode_before_data;
|
||||
pcpa_callback* binary_mode_after_cb;
|
||||
void* binary_mode_after_data;
|
||||
// char* field_0x254;
|
||||
pcp_parse_data_t recv_data;
|
||||
pcp_send_data_t send_data;
|
||||
|
||||
// Our additions
|
||||
pcpa_callback* before_cb;
|
||||
} pcpa_t;
|
||||
|
||||
void pcpaClose(pcpa_t* stream);
|
||||
void pcpaCloseBinary(pcpa_t* stream);
|
||||
char* pcpaGetKeyword(pcpa_t* stream, uint keyword_num);
|
||||
e_pcpa_t pcpaInitStream(pcpa_t* stream);
|
||||
e_pcpa_t pcpaOpenServerWithBinary(pcpa_t* stream, int open_mode, ushort port, ushort binary_port, undefined4 param_5);
|
||||
e_pcpa_t pcpaRecvBinary(pcpa_t* stream, undefined4 something);
|
||||
e_pcpa_t pcpaSendBinary(pcpa_t* stream, undefined4 something);
|
||||
e_pcpa_t pcpaServer(pcpa_t* stream, timeout_t timeout_ms);
|
||||
e_pcpa_t pcpaSetAfterBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
|
||||
e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
|
||||
e_pcpa_t pcpaSetBinaryMode(pcpa_t* stream, binary_mode_t binary_mode);
|
||||
e_pcpa_t pcpaSetCallbackFunc(pcpa_t* stream, char* keyword, pcpa_callback* callback, void* data);
|
||||
e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t* stream, pcpa_cb_table_t* callback_table, uint callbacks_max);
|
||||
e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t* stream, byte* recv_buffer, size_t len);
|
||||
e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t* stream, byte* send_buffer, size_t len);
|
||||
pcp_send_data_t* pcpaSetSendPacket(pcpa_t* stream, char* keyword, char* value);
|
||||
pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value);
|
||||
char* pcpaGetCommand(pcpa_t* pcpa, char* command);
|
||||
#include "pcpp.h"
|
||||
|
||||
typedef enum e_pcpa {
|
||||
e_pcpa_ok = 0,
|
||||
e_pcpa_to = 1,
|
||||
e_pcpa_closed = 2,
|
||||
e_pcpa_no_client = 3,
|
||||
e_pcpa_not_open = -1,
|
||||
e_pcpa_cannot_open = -2,
|
||||
e_pcpa_generic = -3,
|
||||
e_pcpa_param_invalid = -4,
|
||||
e_pcpa_timeout_closed = -5, // TODO: This is wrong (see: pcpaSetCallbackFuncBuffer)
|
||||
e_pcpa_cb_table_full = -9,
|
||||
e_pcpa_stream_unset = -10,
|
||||
e_pcpa_cb_table_unset = -11,
|
||||
e_pcpa_timeout_open = -14,
|
||||
e_pcpa_inval_addr = -17,
|
||||
e_pcpa_already_open = -18,
|
||||
e_pcpa_wsa_noinit = -20,
|
||||
e_pcpa_unknown = -21,
|
||||
} e_pcpa_t;
|
||||
|
||||
e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err);
|
||||
#define _errP2A(err) _pcpaGetErrorFromPcpp(err)
|
||||
|
||||
struct pcpa;
|
||||
typedef void(pcpa_callback)(struct pcpa* stream, void* data);
|
||||
|
||||
typedef struct pcpa_cb_table {
|
||||
char keyword[PCP_KEYWORD_MAX];
|
||||
void* data;
|
||||
pcpa_callback* callback;
|
||||
} pcpa_cb_table_t;
|
||||
|
||||
typedef struct pcpa {
|
||||
pcpp_t pcpp;
|
||||
e_pcpa_t err;
|
||||
uint state;
|
||||
pcpa_cb_table_t* callback_table;
|
||||
uint callback_max;
|
||||
uint callback_count;
|
||||
unsigned char* recv_buffer;
|
||||
size_t recv_buffer_len;
|
||||
unsigned char* send_buffer;
|
||||
size_t send_buffer_len;
|
||||
binary_mode_t binary_mode;
|
||||
pcpa_callback* binary_mode_before_cb;
|
||||
void* binary_mode_before_data;
|
||||
pcpa_callback* binary_mode_after_cb;
|
||||
void* binary_mode_after_data;
|
||||
// char* field_0x254;
|
||||
pcp_parse_data_t recv_data;
|
||||
pcp_send_data_t send_data;
|
||||
|
||||
// Our additions
|
||||
pcpa_callback* before_cb;
|
||||
} pcpa_t;
|
||||
|
||||
void pcpaClose(pcpa_t* stream);
|
||||
void pcpaCloseBinary(pcpa_t* stream);
|
||||
char* pcpaGetKeyword(pcpa_t* stream, uint keyword_num);
|
||||
e_pcpa_t pcpaInitStream(pcpa_t* stream);
|
||||
e_pcpa_t pcpaOpenServerWithBinary(pcpa_t* stream, int open_mode, ushort port, ushort binary_port, undefined4 param_5);
|
||||
e_pcpa_t pcpaRecvBinary(pcpa_t* stream, undefined4 something);
|
||||
e_pcpa_t pcpaSendBinary(pcpa_t* stream, undefined4 something);
|
||||
e_pcpa_t pcpaServer(pcpa_t* stream, timeout_t timeout_ms);
|
||||
e_pcpa_t pcpaSetAfterBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
|
||||
e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
|
||||
e_pcpa_t pcpaSetBinaryMode(pcpa_t* stream, binary_mode_t binary_mode);
|
||||
e_pcpa_t pcpaSetCallbackFunc(pcpa_t* stream, char* keyword, pcpa_callback* callback, void* data);
|
||||
e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t* stream, pcpa_cb_table_t* callback_table, uint callbacks_max);
|
||||
e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t* stream, byte* recv_buffer, size_t len);
|
||||
e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t* stream, byte* send_buffer, size_t len);
|
||||
pcp_send_data_t* pcpaSetSendPacket(pcpa_t* stream, char* keyword, char* value);
|
||||
pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value);
|
||||
char* pcpaGetCommand(pcpa_t* pcpa, char* command);
|
||||
|
1758
src/micetools/lib/libpcp/pcpp.c
Normal file
1758
src/micetools/lib/libpcp/pcpp.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,87 +1,95 @@
|
||||
#include "pcpt.h"
|
||||
|
||||
#define PCPP_CLOSED 0
|
||||
#define PCPP_OPEN 1
|
||||
|
||||
typedef enum e_pcpp {
|
||||
e_pcpp_ok = 0,
|
||||
e_pcpp_to = 1,
|
||||
e_pcpp_closed = 2,
|
||||
e_pcpp_no_client = 3,
|
||||
|
||||
e_pcpp_not_open = -1,
|
||||
e_pcpp_cannot_open = -2,
|
||||
e_pcpp_already_open = -3,
|
||||
e_pcpp_param_invalid = -5,
|
||||
e_pcpp_timeout_closed = -6,
|
||||
e_pcpp_recv_unset = -10,
|
||||
e_pcpp_timeout_open = -12,
|
||||
e_pcpp_inval_addr = -15,
|
||||
e_pcpp_wsa_noinit = -16,
|
||||
e_pcpp_unknown = -17,
|
||||
} e_pcpp_t;
|
||||
|
||||
e_pcpp_t _pcppGetErrorFromPcpt(e_pcpt_t err);
|
||||
#define _errT2P(err) _pcppGetErrorFromPcpt(err)
|
||||
|
||||
typedef struct pcpp {
|
||||
pcpt_t sock;
|
||||
pcpt_t data_sock;
|
||||
uint field_0xb8; // Some sort of timeout
|
||||
int last_active;
|
||||
uint state;
|
||||
e_pcpp_t err;
|
||||
pcp_parse_data_t* recv_data_buffer;
|
||||
char read_bytes_buf[PCP_BUF_MAX];
|
||||
uint read_bytes_size;
|
||||
uint read_bytes_num;
|
||||
pcp_send_data_t* resp_buffer;
|
||||
uint resp_buffer_len;
|
||||
char send_buf[PCP_SEND_BUF_MAX];
|
||||
size_t send_buf_len;
|
||||
uint field_0x1e8;
|
||||
char* send_binary_buf;
|
||||
uint field_0x1f0;
|
||||
char* recv_binary_buf;
|
||||
size_t field_0x1f8;
|
||||
uint field_0x1fc;
|
||||
size_t recv_binary_buf_len;
|
||||
// All some sort of timeout I think
|
||||
uint field_0x204;
|
||||
uint field_0x208;
|
||||
uint field_0x20c;
|
||||
uint field_0x210;
|
||||
int field_0x214;
|
||||
int open;
|
||||
} pcpp_t;
|
||||
|
||||
pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* stream, char* key, char* value);
|
||||
pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, int* lenout);
|
||||
bool pcppCheckPrompt(pcpp_t* stream);
|
||||
e_pcpp_t pcppCheckRecvMsg(char* recv_data, size_t buf_len, int param_3);
|
||||
uint pcppCheckStr(char* param_1, uint* pcp_len, int* pcp_overflow);
|
||||
void pcppClose(pcpp_t* stream);
|
||||
void pcppCloseBinary(pcpp_t* stream);
|
||||
e_pcpp_t pcppGetBlockingTime(uint param_1, int param_2, pcpp_t* stream, int param_4, uint* blocking_time);
|
||||
char* pcppGetCommand(pcp_parse_data_t* pcpa, char* command);
|
||||
char* pcppGetKeyword(pcp_parse_data_t* recvData, uint keyword_num);
|
||||
SOCKET pcppGetServerSocket(pcpp_t* stream, int which);
|
||||
e_pcpp_t pcppInitStream(pcpp_t* stream);
|
||||
e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout);
|
||||
e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port);
|
||||
e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, ushort port, undefined4 param_4);
|
||||
e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv);
|
||||
e_pcpp_t pcppRecvBinary(pcpp_t* stream, char* recv_buf, size_t buf_len, uint param_4);
|
||||
uint pcppRecvCheck(char* buf, int* found_at);
|
||||
e_pcpp_t pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3);
|
||||
e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout);
|
||||
e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3);
|
||||
e_pcpp_t pcppSendBinary(pcpp_t* stream, char* send_binary_buffer, size_t param_3, uint param_4);
|
||||
e_pcpp_t pcppSendPrompt(pcpp_t* stream, uint param_2, int param_3);
|
||||
e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, int param_3);
|
||||
e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, timeout_t timeout_ms);
|
||||
e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t timeout_ms);
|
||||
pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, char* value);
|
||||
e_pcpp_t pcpp_something(amtime_t* now, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, char* send_buf,
|
||||
size_t* send_len, undefined4 param_7, undefined4 param_8, e_pcpp_t fallback_err);
|
||||
void pcppResetRead(pcpp_t* param_1);
|
||||
#include "pcpt.h"
|
||||
|
||||
#define PCPP_CLOSED 0
|
||||
#define PCPP_OPEN 1
|
||||
|
||||
typedef enum e_pcpp {
|
||||
e_pcpp_ok = 0,
|
||||
e_pcpp_to = 1,
|
||||
e_pcpp_closed = 2,
|
||||
e_pcpp_no_client = 3,
|
||||
|
||||
e_pcpp_not_open = -1,
|
||||
e_pcpp_cannot_open = -2,
|
||||
e_pcpp_already_open = -3,
|
||||
e_pcpp_param_invalid = -5,
|
||||
e_pcpp_timeout_closed = -6,
|
||||
e_pcpp_recv_unset = -10,
|
||||
e_pcpp_timeout_open = -12,
|
||||
e_pcpp_inval_addr = -15,
|
||||
e_pcpp_wsa_noinit = -16,
|
||||
e_pcpp_unknown = -17,
|
||||
|
||||
e_pcpp_uk1 = -14,
|
||||
e_pcpp_uk2 = -13,
|
||||
e_pcpp_uk3 = -11,
|
||||
e_pcpp_uk4 = -9,
|
||||
e_pcpp_uk5 = -8,
|
||||
e_pcpp_uk6 = -7,
|
||||
e_pcpp_uk7 = -4,
|
||||
} e_pcpp_t;
|
||||
|
||||
e_pcpp_t _pcppGetErrorFromPcpt(e_pcpt_t err);
|
||||
#define _errT2P(err) _pcppGetErrorFromPcpt(err)
|
||||
|
||||
typedef struct pcpp {
|
||||
pcpt_t sock;
|
||||
pcpt_t data_sock;
|
||||
uint field_0xb8; // Some sort of timeout
|
||||
int last_active;
|
||||
uint state;
|
||||
e_pcpp_t err;
|
||||
pcp_parse_data_t* recv_data_buffer;
|
||||
unsigned char read_bytes_buf[PCP_BUF_MAX];
|
||||
uint read_bytes_size;
|
||||
uint read_bytes_num;
|
||||
pcp_send_data_t* resp_buffer;
|
||||
uint resp_buffer_len;
|
||||
unsigned char send_buf[PCP_SEND_BUF_MAX];
|
||||
size_t send_buf_len;
|
||||
uint field_0x1e8;
|
||||
unsigned char* send_binary_buf;
|
||||
uint field_0x1f0;
|
||||
unsigned char* recv_binary_buf;
|
||||
size_t field_0x1f8;
|
||||
uint field_0x1fc;
|
||||
size_t recv_binary_buf_len;
|
||||
// All some sort of timeout I think
|
||||
uint field_0x204;
|
||||
uint field_0x208;
|
||||
uint field_0x20c;
|
||||
uint field_0x210;
|
||||
int field_0x214;
|
||||
int open;
|
||||
} pcpp_t;
|
||||
|
||||
pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* stream, char* key, char* value);
|
||||
pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout);
|
||||
bool pcppCheckPrompt(pcpp_t* stream);
|
||||
e_pcpp_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3);
|
||||
uint pcppCheckStr(unsigned char* param_1, uint* pcp_len, int* pcp_overflow);
|
||||
void pcppClose(pcpp_t* stream);
|
||||
void pcppCloseBinary(pcpp_t* stream);
|
||||
e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t param_2, pcpp_t* stream, int param_4, uint* blocking_time);
|
||||
char* pcppGetCommand(pcp_parse_data_t* pcpa, char* command);
|
||||
char* pcppGetKeyword(pcp_parse_data_t* recvData, uint keyword_num);
|
||||
SOCKET pcppGetServerSocket(pcpp_t* stream, int which);
|
||||
e_pcpp_t pcppInitStream(pcpp_t* stream);
|
||||
e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout);
|
||||
e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port);
|
||||
e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, ushort port, undefined4 param_4);
|
||||
e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv);
|
||||
e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, uint param_4);
|
||||
uint pcppRecvCheck(unsigned char* buf, int* found_at);
|
||||
e_pcpp_t pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3);
|
||||
e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout);
|
||||
e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3);
|
||||
e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, uint param_4);
|
||||
e_pcpp_t pcppSendPrompt(pcpp_t* stream, uint param_2, timeout_t timeout_ms);
|
||||
e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeout_ms);
|
||||
e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, timeout_t timeout_ms);
|
||||
e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t timeout_ms);
|
||||
pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, char* value);
|
||||
e_pcpp_t pcpp_something(amtime_t* now, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, unsigned char* send_buf,
|
||||
size_t* send_len, undefined4 param_7, undefined4 param_8, e_pcpp_t fallback_err);
|
||||
void pcppResetRead(pcpp_t* param_1);
|
||||
|
758
src/micetools/lib/libpcp/pcpt.c
Normal file
758
src/micetools/lib/libpcp/pcpt.c
Normal file
@ -0,0 +1,758 @@
|
||||
#include "pcpt.h"
|
||||
|
||||
e_pcpt_t _pcptGetErrorFromWin(int err) {
|
||||
switch (err) {
|
||||
case WSAEBADF:
|
||||
case WSAEINVAL:
|
||||
case WSAENOTSOCK:
|
||||
case WSAEISCONN:
|
||||
return e_pcpt_wsa2_generic;
|
||||
case WSAEMFILE:
|
||||
return e_pcpt_cannot_open;
|
||||
case WSAEWOULDBLOCK:
|
||||
case WSAETIMEDOUT:
|
||||
return e_pcpt_to;
|
||||
case WSAEADDRNOTAVAIL:
|
||||
return e_pcpt_inval_addr;
|
||||
case WSAECONNABORTED:
|
||||
case WSAECONNRESET:
|
||||
return e_pcpt_closed;
|
||||
case WSAENOBUFS:
|
||||
return e_pcpt_nobufs;
|
||||
case WSANOTINITIALISED:
|
||||
return e_pcpt_wsa_noinit;
|
||||
default:
|
||||
return e_pcpt_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
e_pcpt_t pcptInitStream(pcpt_t *sock) {
|
||||
SOCKET s;
|
||||
|
||||
if (sock == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == SOCKET_INVAL) return _errW2T(WSAGetLastError());
|
||||
closesocket(s);
|
||||
|
||||
sock->client_open = 0;
|
||||
sock->open = PCPT_CLOSED;
|
||||
sock->client_event = NULL;
|
||||
sock->server_event = NULL;
|
||||
sock->send_buf = NULL;
|
||||
sock->send_buf_count = NULL;
|
||||
sock->recv_buf_count = NULL;
|
||||
sock->recv_buf = NULL;
|
||||
sock->server_sock = SOCKET_INVAL;
|
||||
sock->client_sock = SOCKET_INVAL;
|
||||
sock->err = e_pcpt_unknown;
|
||||
memset(&sock->client_addr, 0, sizeof sock->client_addr);
|
||||
sock->field_0x58 = 0;
|
||||
sock->tcp_nodelay = 0;
|
||||
sock->config_0 = 12000;
|
||||
sock->config_1 = 5;
|
||||
sock->so_linger = 1;
|
||||
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
|
||||
void pcptClose(pcpt_t *sock) {
|
||||
if (sock == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sock->server_sock != SOCKET_INVAL) {
|
||||
WSAEventSelect(sock->server_sock, 0, 0);
|
||||
WSACloseEvent(sock->server_event);
|
||||
sock->server_event = NULL;
|
||||
closesocket(sock->server_sock);
|
||||
sock->server_sock = SOCKET_INVAL;
|
||||
}
|
||||
if (sock->client_sock != SOCKET_INVAL) {
|
||||
WSAEventSelect(sock->client_sock, 0, 0);
|
||||
WSACloseEvent(sock->client_event);
|
||||
sock->client_event = NULL;
|
||||
closesocket(sock->client_sock);
|
||||
sock->client_sock = SOCKET_INVAL;
|
||||
}
|
||||
sock->client_open = 0;
|
||||
sock->open = PCPT_CLOSED;
|
||||
sock->err = e_pcpt_unknown;
|
||||
if (sock->client_event != NULL) {
|
||||
WSACloseEvent(sock->client_event);
|
||||
sock->client_event = NULL;
|
||||
}
|
||||
if (sock->server_event != NULL) {
|
||||
WSACloseEvent(sock->server_event);
|
||||
sock->server_event = NULL;
|
||||
}
|
||||
sock->send_buf = NULL;
|
||||
sock->send_buf_count = NULL;
|
||||
sock->recv_buf_count = NULL;
|
||||
sock->recv_buf = NULL;
|
||||
memset(&sock->client_addr, 0, sizeof sock->client_addr);
|
||||
sock->field_0x58 = 0;
|
||||
}
|
||||
|
||||
void pcptCloseDataSock(pcpt_t *sock) {
|
||||
if (sock == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return;
|
||||
}
|
||||
if (sock->field_0x58 != 0) {
|
||||
sock->open = PCPT_LISTENING;
|
||||
}
|
||||
sock->client_open = 0;
|
||||
if (sock->client_sock != SOCKET_INVAL) {
|
||||
WSAEventSelect(sock->client_sock, 0, 0);
|
||||
WSACloseEvent(sock->client_event);
|
||||
sock->client_event = NULL;
|
||||
closesocket(sock->client_sock);
|
||||
sock->client_sock = SOCKET_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
e_pcpt_t pcptAcceptServer(pcpt_t *stream, timeout_t timeout_ms) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
e_pcpt_t err = pcptCheckEvent(stream->server_event, timeout_ms, stream->server_sock, FD_ACCEPT);
|
||||
if (err != e_pcpt_ok) return err;
|
||||
|
||||
int addrlen = 16;
|
||||
SOCKET client = accept(stream->server_sock, &stream->client_addr, &addrlen);
|
||||
stream->client_sock = client;
|
||||
if (client == SOCKET_INVAL) return _errW2T(GetLastError());
|
||||
|
||||
WSAEVENT event = WSACreateEvent();
|
||||
stream->client_event = event;
|
||||
if (event == NULL) {
|
||||
closesocket(stream->client_sock);
|
||||
stream->client_sock = SOCKET_INVAL;
|
||||
return e_pcpt_unknown;
|
||||
}
|
||||
WSAEventSelect(stream->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE);
|
||||
|
||||
uint so_linger = (uint)(!!stream->so_linger);
|
||||
setsockopt(stream->client_sock, SOL_SOCKET, SO_LINGER, (void *)&so_linger, sizeof so_linger);
|
||||
|
||||
uint nodelay = (uint)(!stream->tcp_nodelay);
|
||||
setsockopt(stream->client_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&nodelay, sizeof nodelay);
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
|
||||
e_pcpt_t pcptCheckConnectAble(pcpt_t *stream, timeout_t timeout_ms) {
|
||||
DWORD DVar1;
|
||||
uint uVar3;
|
||||
HANDLE event;
|
||||
bool bVar5;
|
||||
e_pcpt_t local_44;
|
||||
u_long local_40;
|
||||
amtime_t now;
|
||||
amtime_t start;
|
||||
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
amiTimerGet(&start);
|
||||
DVar1 = timeout_ms;
|
||||
|
||||
if (timeout_ms == TIMEOUT_NONE) DVar1 = TIMEOUT_NONE;
|
||||
|
||||
while (DVar1 = WaitForSingleObject(stream->client_event, DVar1), DVar1 == WAIT_TIMEOUT) {
|
||||
LAB_004589c8:
|
||||
amiTimerGet(&now);
|
||||
uVar3 = _amTimeDelta(now, start);
|
||||
if (timeout_ms <= uVar3) return e_pcpt_to;
|
||||
|
||||
DVar1 = timeout_ms - uVar3;
|
||||
}
|
||||
|
||||
if (DVar1 == 0) {
|
||||
WSANETWORKEVENTS net_events;
|
||||
|
||||
if (FAILED(WSAEnumNetworkEvents(stream->client_sock, stream->client_event, &net_events))) {
|
||||
bVar5 = WSAGetLastError() == WSAEWOULDBLOCK;
|
||||
} else {
|
||||
if ((net_events.lNetworkEvents & 0x10) != 0 &&
|
||||
net_events.iErrorCode[FD_CONNECT_BIT] == 0) {
|
||||
local_44 = e_pcpt_ok;
|
||||
goto LAB_00458a1e;
|
||||
}
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) goto LAB_004589c8;
|
||||
bVar5 = net_events.iErrorCode[FD_CONNECT_BIT] == WSAECONNREFUSED;
|
||||
}
|
||||
if (bVar5) goto LAB_004589c8;
|
||||
}
|
||||
local_44 = e_pcpt_wsa2_generic;
|
||||
|
||||
LAB_00458a1e:
|
||||
local_40 = 0;
|
||||
WSAEventSelect(stream->client_sock, 0, 0);
|
||||
WSACloseEvent(stream->client_event);
|
||||
stream->client_event = NULL;
|
||||
if (local_44 != e_pcpt_ok) {
|
||||
closesocket(stream->client_sock);
|
||||
stream->client_sock = SOCKET_INVAL;
|
||||
return local_44;
|
||||
}
|
||||
ioctlsocket(stream->client_sock, FIONBIO, &local_40);
|
||||
|
||||
event = WSACreateEvent();
|
||||
stream->client_event = event;
|
||||
if (event != NULL) {
|
||||
WSAEventSelect(stream->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE);
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
closesocket(stream->client_sock);
|
||||
stream->client_sock = SOCKET_INVAL;
|
||||
return e_pcpt_unknown;
|
||||
}
|
||||
|
||||
e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask) {
|
||||
amtime_t now;
|
||||
amtime_t start;
|
||||
WSANETWORKEVENTS networkEvents;
|
||||
|
||||
amiTimerGet(&start);
|
||||
now.seconds = start.seconds;
|
||||
now.microseconds = start.microseconds;
|
||||
DWORD wait_timeout = timeout_ms;
|
||||
if (timeout_ms == TIMEOUT_NONE) wait_timeout = TIMEOUT_NONE;
|
||||
|
||||
if (event == NULL) {
|
||||
PCP_LOG("Error : EVENT HANDLE error\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
event_mask &= 0xffffffdf;
|
||||
|
||||
while (1) {
|
||||
DWORD err = WaitForSingleObject(event, wait_timeout);
|
||||
if ((err != WAIT_TIMEOUT && err != 0) || FAILED(err)) {
|
||||
return e_pcpt_wsa2_generic;
|
||||
}
|
||||
|
||||
if (err != WAIT_TIMEOUT) {
|
||||
if (FAILED(WSAEnumNetworkEvents(socket, event, &networkEvents)))
|
||||
return e_pcpt_wsa2_generic;
|
||||
|
||||
if ((networkEvents.lNetworkEvents & 0x20) != 0) return e_pcpt_closed;
|
||||
|
||||
if ((event_mask & networkEvents.lNetworkEvents) != 0) return e_pcpt_ok;
|
||||
}
|
||||
|
||||
if (timeout_ms != TIMEOUT_NONE) {
|
||||
amiTimerGet(&now);
|
||||
uint elapsed = _amTimeDelta(now, start);
|
||||
if ((uint)timeout_ms <= elapsed) return e_pcpt_to;
|
||||
|
||||
wait_timeout = timeout_ms - elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e_pcpt_t pcptOpenDataSockServer(pcpt_t *sock, timeout_t timeout_ms) {
|
||||
if (sock == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
if (sock->open == PCPT_CONNECTED) return e_pcpt_already_open;
|
||||
if (sock->open == PCPT_CLOSED) return e_pcpt_not_open;
|
||||
|
||||
if ((sock->client_sock == SOCKET_INVAL)) {
|
||||
e_pcpt_t err = pcptAcceptServer(sock, timeout_ms);
|
||||
if (err != e_pcpt_ok) return err;
|
||||
}
|
||||
|
||||
sock->open = PCPT_CONNECTED;
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
|
||||
e_pcpt_t pcptOpenServer(pcpt_t *stream, int open_mode, ushort port) {
|
||||
e_pcpt_t err;
|
||||
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
if (stream->server_sock != SOCKET_INVAL || stream->client_sock != SOCKET_INVAL)
|
||||
return stream->err = e_pcpt_already_open;
|
||||
|
||||
amtime_t start;
|
||||
amiTimerGet(&start);
|
||||
stream->field_0x58 = 1;
|
||||
stream->open = PCPT_CLOSED;
|
||||
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
stream->server_sock = s;
|
||||
|
||||
if (s == SOCKET_INVAL) return stream->err = _errW2T(GetLastError());
|
||||
|
||||
uint reuseaddr = 1;
|
||||
if (FAILED(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddr, 4))) {
|
||||
err = _errW2T(GetLastError());
|
||||
closesocket(stream->server_sock);
|
||||
stream->server_sock = SOCKET_INVAL;
|
||||
return stream->err = err;
|
||||
}
|
||||
|
||||
SOCKADDR_IN addr = { .sin_family = AF_INET,
|
||||
.sin_port = ntohs(port),
|
||||
.sin_addr.s_addr = ntohl(0) };
|
||||
if (open_mode != OPEN_MODE_GLOBAL) {
|
||||
INT len = sizeof &addr.sin_addr.s_addr;
|
||||
|
||||
WSAStringToAddressW(L"127.0.0.1", AF_INET, NULL, (LPSOCKADDR)&addr.sin_addr.s_addr, &len);
|
||||
}
|
||||
|
||||
if (FAILED(bind(stream->server_sock, (SOCKADDR *)&addr, sizeof addr))) {
|
||||
err = _errW2T(GetLastError());
|
||||
closesocket(stream->server_sock);
|
||||
stream->server_sock = SOCKET_INVAL;
|
||||
return stream->err = err;
|
||||
}
|
||||
if (FAILED(listen(stream->server_sock, 128))) {
|
||||
err = _errW2T(GetLastError());
|
||||
closesocket(stream->server_sock);
|
||||
stream->server_sock = SOCKET_INVAL;
|
||||
return stream->err = err;
|
||||
}
|
||||
|
||||
WSAEVENT event = WSACreateEvent();
|
||||
stream->server_event = event;
|
||||
if (event != NULL) {
|
||||
WSAEventSelect(stream->server_sock, event, FD_CLOSE | FD_ACCEPT);
|
||||
stream->open = PCPT_LISTENING;
|
||||
stream->client_open = 0;
|
||||
return stream->err = e_pcpt_ok;
|
||||
}
|
||||
closesocket(stream->server_sock);
|
||||
stream->server_sock = SOCKET_INVAL;
|
||||
|
||||
return stream->err = e_pcpt_unknown;
|
||||
}
|
||||
|
||||
e_pcpt_t pcptRecv(pcpt_t *sock, unsigned char *recv_buf, size_t *recv_buf_len,
|
||||
timeout_t timeout_ms) {
|
||||
e_pcpt_t err;
|
||||
amtime_t now;
|
||||
amtime_t start;
|
||||
|
||||
if (sock == NULL || recv_buf == NULL || recv_buf_len == NULL) {
|
||||
printf("%p %p %p\n", sock, recv_buf, recv_buf_len);
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open;
|
||||
if (sock->client_open != 0) return sock->err = e_pcpt_already_connected;
|
||||
|
||||
sock->recv_buf = recv_buf;
|
||||
sock->recv_buf_count = recv_buf_len;
|
||||
sock->client_open = 3;
|
||||
|
||||
if (sock->open == PCPT_LISTENING && sock->field_0x58 != 0) {
|
||||
amiTimerGet(&start);
|
||||
sock->err = err = pcptOpenDataSockServer(sock, timeout_ms);
|
||||
if (err == e_pcpt_to) return e_pcpt_to;
|
||||
|
||||
if (err != e_pcpt_ok) {
|
||||
pcptCloseDataSock(sock);
|
||||
return sock->err;
|
||||
}
|
||||
|
||||
if (timeout_ms != TIMEOUT_NONE) {
|
||||
amiTimerGet(&now);
|
||||
uint elapsed = _amTimeDelta(now, start);
|
||||
|
||||
if (elapsed < timeout_ms)
|
||||
timeout_ms = timeout_ms - elapsed;
|
||||
else
|
||||
timeout_ms = 0;
|
||||
}
|
||||
}
|
||||
sock->err = err = pcptCheckEvent(sock->client_event, timeout_ms, sock->client_sock, FD_READ);
|
||||
if (err == e_pcpt_to) return e_pcpt_to;
|
||||
|
||||
sock->client_open = 0;
|
||||
if (err == e_pcpt_ok) {
|
||||
size_t recv_count =
|
||||
recv(sock->client_sock, (char *)sock->recv_buf, *sock->recv_buf_count, 0);
|
||||
if (0 < (int)recv_count) {
|
||||
*recv_buf_len = recv_count;
|
||||
sock->err = e_pcpt_ok;
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
|
||||
if (recv_count == 0) {
|
||||
pcptCloseDataSock(sock);
|
||||
return sock->err = e_pcpt_closed;
|
||||
}
|
||||
sock->err = _errW2T(GetLastError());
|
||||
}
|
||||
|
||||
pcptCloseDataSock(sock);
|
||||
return sock->err;
|
||||
}
|
||||
|
||||
e_pcpt_t pcptSend(pcpt_t *sock, unsigned char *send_buf, size_t *send_len, uint param_4,
|
||||
timeout_t timeout_ms) {
|
||||
e_pcpt_t err;
|
||||
amtime_t now;
|
||||
amtime_t start_time;
|
||||
|
||||
if (sock == NULL || send_buf == NULL || send_len == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open;
|
||||
if (sock->client_open != 0) return sock->err = e_pcpt_already_connected;
|
||||
|
||||
sock->send_buf_count = send_len;
|
||||
sock->send_buf = send_buf;
|
||||
sock->client_open = 2;
|
||||
sock->field_0x14 = param_4;
|
||||
sock->field_0x54 = 0;
|
||||
|
||||
if (sock->open == PCPT_LISTENING && sock->field_0x58 != 0) {
|
||||
amiTimerGet(&start_time);
|
||||
err = pcptOpenDataSockServer(sock, timeout_ms);
|
||||
sock->err = err;
|
||||
if (err == e_pcpt_to) return e_pcpt_to;
|
||||
|
||||
if (err == e_pcpt_ok) {
|
||||
amiTimerGet(&now);
|
||||
uint elapsed = _amTimeDelta(now, start_time);
|
||||
if (timeout_ms != TIMEOUT_NONE) {
|
||||
if (elapsed < timeout_ms)
|
||||
timeout_ms = timeout_ms - elapsed;
|
||||
else
|
||||
timeout_ms = 0;
|
||||
}
|
||||
goto LAB_0045930e;
|
||||
}
|
||||
} else {
|
||||
LAB_0045930e:
|
||||
err = pcptSendAllMsg(sock, timeout_ms);
|
||||
sock->err = err;
|
||||
if (err == e_pcpt_to) {
|
||||
return e_pcpt_to;
|
||||
}
|
||||
sock->client_open = 0;
|
||||
if (err == e_pcpt_ok) return err;
|
||||
}
|
||||
pcptCloseDataSock(sock);
|
||||
|
||||
return sock->err;
|
||||
}
|
||||
|
||||
e_pcpt_t pcptSendAllMsg(pcpt_t *sock, timeout_t timeout_ms) {
|
||||
size_t sVar1;
|
||||
bool bVar2;
|
||||
e_pcpt_t err;
|
||||
bool bVar3;
|
||||
amtime_t now;
|
||||
amtime_t start;
|
||||
|
||||
if (sock == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
if (sock->send_buf == NULL || sock->send_buf_count == NULL) {
|
||||
PCP_LOG("error send buffer isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
|
||||
bVar3 = sock->field_0x54 == 0;
|
||||
amiTimerGet(&start);
|
||||
sVar1 = *sock->send_buf_count;
|
||||
while (1) {
|
||||
if (sVar1 == 0) {
|
||||
sock->field_0x54 = 0;
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
|
||||
bVar2 = false;
|
||||
amiTimerGet(&now);
|
||||
uint elapsed = _amTimeDelta(now, start);
|
||||
if (timeout_ms != TIMEOUT_NONE && timeout_ms < elapsed) return e_pcpt_to;
|
||||
|
||||
uint wait_time;
|
||||
if (bVar3) {
|
||||
wait_time = timeout_ms;
|
||||
if (timeout_ms != TIMEOUT_NONE) wait_time = timeout_ms - elapsed;
|
||||
} else {
|
||||
if ((timeout_ms == TIMEOUT_NONE) ||
|
||||
(wait_time = timeout_ms - elapsed,
|
||||
sock->field_0x14 <= wait_time && wait_time != sock->field_0x14)) {
|
||||
wait_time = sock->field_0x14;
|
||||
bVar2 = true;
|
||||
}
|
||||
}
|
||||
int sent = send(sock->client_sock, (char *)sock->send_buf, *sock->send_buf_count, 0);
|
||||
if (sent == -1) {
|
||||
err = _errW2T(GetLastError());
|
||||
if (err != e_pcpt_to) return err;
|
||||
|
||||
err = pcptCheckEvent(sock->client_event, wait_time, sock->client_sock, FD_WRITE);
|
||||
if (err == e_pcpt_to) {
|
||||
if (!bVar2) return e_pcpt_to;
|
||||
|
||||
sock->field_0x54 = 0;
|
||||
return e_pcpt_NO_IDEA_WHAT_THIS_IS;
|
||||
}
|
||||
|
||||
if (err != e_pcpt_ok) return err;
|
||||
} else {
|
||||
sock->send_buf = sock->send_buf + sent;
|
||||
sock->field_0x54 = 1;
|
||||
*sock->send_buf_count = *sock->send_buf_count - sent;
|
||||
}
|
||||
|
||||
bVar3 = false;
|
||||
sVar1 = *sock->send_buf_count;
|
||||
}
|
||||
}
|
||||
|
||||
void pcptSetConfig(pcpt_t *stream, uint config, uint value) {
|
||||
if (stream == NULL) {
|
||||
PCP_LOG("error don\'t set stream\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (config) {
|
||||
case PCPT_CONFIG_0:
|
||||
stream->config_0 = value;
|
||||
break;
|
||||
case PCPT_CONFIG_1:
|
||||
stream->config_1 = value;
|
||||
break;
|
||||
case PCPT_SO_LINGER:
|
||||
stream->so_linger = value;
|
||||
break;
|
||||
case PCPT_TCP_NODELAY:
|
||||
stream->tcp_nodelay = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: TIDY
|
||||
|
||||
e_pcpt_t pcptIsBusy(pcpt_t *sock, timeout_t timeout_ms) {
|
||||
bool bVar1;
|
||||
bool bVar2;
|
||||
uint uVar3;
|
||||
uint uVar4;
|
||||
SOCKET SVar5;
|
||||
WSAEVENT event;
|
||||
int iVar7;
|
||||
e_pcpt_t eVar8;
|
||||
u_long timeout_ms_00;
|
||||
uint uVar10;
|
||||
amtime_t local_18;
|
||||
amtime_t local_10;
|
||||
amtime_t local_8;
|
||||
|
||||
timeout_ms_00 = timeout_ms;
|
||||
if (sock == NULL) {
|
||||
PCP_LOG("error PCP stream isn\'t set\n");
|
||||
return e_pcpt_pointer_unset;
|
||||
}
|
||||
switch (sock->client_open) {
|
||||
case 0:
|
||||
sock->err = e_pcpt_no_client;
|
||||
return sock->err;
|
||||
case 1:
|
||||
if (sock->open != PCPT_CLOSED) {
|
||||
sock->err = e_pcpt_cannot_open;
|
||||
sock->client_open = 0;
|
||||
return sock->err;
|
||||
}
|
||||
amiTimerGet(&local_10);
|
||||
uVar10 = timeout_ms_00;
|
||||
do {
|
||||
bVar1 = false;
|
||||
bVar2 = false;
|
||||
amiTimerGet(&local_18);
|
||||
if (uVar10 != TIMEOUT_NONE) {
|
||||
uVar3 = _amTimeDelta(local_18, local_10);
|
||||
if (uVar3 < uVar10) {
|
||||
timeout_ms_00 = uVar10 - uVar3;
|
||||
} else {
|
||||
bVar2 = true;
|
||||
timeout_ms_00 = 0;
|
||||
}
|
||||
}
|
||||
amiTimerGet(&local_18);
|
||||
uVar4 = _amTimeMs(local_18) - sock->field_0x40;
|
||||
uVar3 = sock->config_0;
|
||||
if (uVar3 < uVar4) {
|
||||
timeout_ms_00 = 0;
|
||||
LAB_00459626:
|
||||
bVar1 = true;
|
||||
} else {
|
||||
if ((uVar10 == TIMEOUT_NONE) || (uVar3 < timeout_ms_00)) {
|
||||
timeout_ms_00 = uVar3 - uVar4;
|
||||
goto LAB_00459626;
|
||||
}
|
||||
}
|
||||
eVar8 = pcptCheckConnectAble(sock, timeout_ms_00);
|
||||
sock->err = eVar8;
|
||||
if (eVar8 != e_pcpt_to) {
|
||||
sock->client_open = 0;
|
||||
if (eVar8 == e_pcpt_ok) {
|
||||
sock->open = PCPT_CONNECTED;
|
||||
return sock->err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (bVar1) {
|
||||
WSAEventSelect(sock->client_sock, 0, 0);
|
||||
WSACloseEvent(sock->client_event);
|
||||
sock->client_event = NULL;
|
||||
closesocket(sock->client_sock);
|
||||
sock->client_sock = SOCKET_INVAL;
|
||||
SVar5 = socket(2, 1, 0);
|
||||
sock->client_sock = SVar5;
|
||||
if (SVar5 == SOCKET_INVAL) goto LAB_004599cf;
|
||||
event = WSACreateEvent();
|
||||
sock->client_event = event;
|
||||
if (event == NULL) {
|
||||
closesocket(sock->client_sock);
|
||||
sock->err = e_pcpt_unknown;
|
||||
sock->client_sock = SOCKET_INVAL;
|
||||
return sock->err;
|
||||
}
|
||||
WSAEventSelect(sock->client_sock, event, FD_CONNECT | FD_CLOSE);
|
||||
iVar7 = connect(sock->client_sock, &sock->client_addr, 16);
|
||||
if (iVar7 != -1) {
|
||||
WSAEventSelect(sock->client_sock, 0, 0);
|
||||
WSACloseEvent(sock->client_event);
|
||||
sock->client_event = NULL;
|
||||
timeout_ms = 0;
|
||||
ioctlsocket(sock->client_sock, FIONBIO, (u_long *)&timeout_ms);
|
||||
event = WSACreateEvent();
|
||||
sock->client_event = event;
|
||||
if (event != NULL) {
|
||||
WSAEventSelect(sock->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE);
|
||||
sock->err = e_pcpt_ok;
|
||||
sock->client_open = 0;
|
||||
sock->open = PCPT_CONNECTED;
|
||||
return e_pcpt_ok;
|
||||
}
|
||||
closesocket(sock->client_sock);
|
||||
sock->err = e_pcpt_unknown;
|
||||
sock->client_sock = SOCKET_INVAL;
|
||||
return sock->err;
|
||||
}
|
||||
amiTimerGet(&local_8);
|
||||
sock->field_0x40 = _amTimeMs(local_8);
|
||||
} else {
|
||||
if (bVar2) {
|
||||
sock->err = e_pcpt_to;
|
||||
return e_pcpt_to;
|
||||
}
|
||||
}
|
||||
uVar10 = timeout_ms;
|
||||
} while (sock->err == e_pcpt_to);
|
||||
break;
|
||||
case 2:
|
||||
if (sock->open == PCPT_CLOSED) {
|
||||
sock->err = e_pcpt_not_open;
|
||||
return e_pcpt_not_open;
|
||||
}
|
||||
if ((sock->open == PCPT_LISTENING) && (sock->field_0x58 != 0)) {
|
||||
amiTimerGet(&local_10);
|
||||
eVar8 = pcptOpenDataSockServer(sock, timeout_ms_00);
|
||||
sock->err = eVar8;
|
||||
if (eVar8 == e_pcpt_to) {
|
||||
return e_pcpt_to;
|
||||
}
|
||||
if (eVar8 != e_pcpt_ok) {
|
||||
LAB_0045997d:
|
||||
pcptCloseDataSock(sock);
|
||||
return sock->err;
|
||||
}
|
||||
amiTimerGet(&local_18);
|
||||
if (timeout_ms_00 != TIMEOUT_NONE) {
|
||||
iVar7 = (local_18.microseconds - local_10.microseconds) / 1000;
|
||||
if (timeout_ms_00 <
|
||||
(uint)((local_18.seconds - local_10.seconds) * 1000 + iVar7)) {
|
||||
timeout_ms_00 =
|
||||
((local_10.seconds - local_18.seconds) * 1000 - iVar7) + timeout_ms_00;
|
||||
} else {
|
||||
timeout_ms_00 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
eVar8 = pcptSendAllMsg(sock, timeout_ms_00);
|
||||
sock->err = eVar8;
|
||||
if (eVar8 != e_pcpt_to) {
|
||||
if (eVar8 != e_pcpt_ok) {
|
||||
pcptCloseDataSock(sock);
|
||||
}
|
||||
sock->client_open = 0;
|
||||
return sock->err;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (sock->open == PCPT_CLOSED) {
|
||||
sock->err = e_pcpt_not_open;
|
||||
return sock->err;
|
||||
}
|
||||
if ((sock->open == PCPT_LISTENING) && (sock->field_0x58 != 0)) {
|
||||
amiTimerGet(&local_10);
|
||||
eVar8 = pcptOpenDataSockServer(sock, timeout_ms_00);
|
||||
sock->err = eVar8;
|
||||
if (eVar8 == e_pcpt_to) {
|
||||
return e_pcpt_to;
|
||||
}
|
||||
if (eVar8 != e_pcpt_ok) goto LAB_0045997d;
|
||||
amiTimerGet(&local_18);
|
||||
if (timeout_ms_00 != TIMEOUT_NONE) {
|
||||
iVar7 = (local_18.microseconds - local_10.microseconds) / 1000;
|
||||
if (timeout_ms_00 <
|
||||
(uint)((local_18.seconds - local_10.seconds) * 1000 + iVar7)) {
|
||||
timeout_ms_00 =
|
||||
((local_10.seconds - local_18.seconds) * 1000 - iVar7) + timeout_ms_00;
|
||||
} else {
|
||||
timeout_ms_00 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
eVar8 = pcptCheckEvent(sock->client_event, timeout_ms_00, sock->client_sock, 1);
|
||||
sock->err = eVar8;
|
||||
if (eVar8 == e_pcpt_to) break;
|
||||
sock->client_open = 0;
|
||||
if (eVar8 != e_pcpt_ok) goto LAB_0045997d;
|
||||
if (sock->recv_buf == NULL || sock->recv_buf_count == NULL) {
|
||||
PCP_LOG("error Recv buffer isn\'t set\n");
|
||||
return sock->err = e_pcpt_recv_unset;
|
||||
}
|
||||
size_t received =
|
||||
recv(sock->client_sock, (char *)sock->recv_buf, *sock->recv_buf_count, 0);
|
||||
if (received < 1) {
|
||||
pcptCloseDataSock(sock);
|
||||
if (received == 0) {
|
||||
sock->err = e_pcpt_closed;
|
||||
return e_pcpt_closed;
|
||||
}
|
||||
LAB_004599cf:
|
||||
return sock->err = _errW2T(GetLastError());
|
||||
}
|
||||
*sock->recv_buf_count = received;
|
||||
default:
|
||||
sock->err = e_pcpt_ok;
|
||||
}
|
||||
return sock->err;
|
||||
}
|
@ -1,65 +1,65 @@
|
||||
#include "pcp.h"
|
||||
|
||||
typedef enum e_pcpt {
|
||||
e_pcpt_ok = 0,
|
||||
e_pcpt_to = 1,
|
||||
e_pcpt_closed = 2,
|
||||
e_pcpt_no_client = 3,
|
||||
|
||||
e_pcpt_not_open = -1,
|
||||
// TODO: Check if these two are the wrong way round!
|
||||
e_pcpt_already_open = -2,
|
||||
e_pcpt_already_connected = -3,
|
||||
e_pcpt_pointer_unset = -4,
|
||||
|
||||
e_pcpt_cannot_open = -8,
|
||||
e_pcpt_nobufs = -9,
|
||||
e_pcpt_wsa2_generic = -10,
|
||||
e_pcpt_inval_addr = -12,
|
||||
|
||||
e_pcpt_NO_IDEA_WHAT_THIS_IS = -13,
|
||||
|
||||
e_pcpt_recv_unset = -15,
|
||||
e_pcpt_wsa_noinit = -16,
|
||||
e_pcpt_unknown = -17,
|
||||
} e_pcpt_t;
|
||||
|
||||
e_pcpt_t _pcptGetErrorFromWin(int err);
|
||||
#define _errW2T(err) _pcptGetErrorFromWin(err)
|
||||
|
||||
typedef struct pcpt {
|
||||
SOCKET server_sock;
|
||||
SOCKET client_sock;
|
||||
int client_open;
|
||||
int open;
|
||||
e_pcpt_t err;
|
||||
uint field_0x14;
|
||||
uint config_0;
|
||||
uint config_1;
|
||||
uint so_linger;
|
||||
uint tcp_nodelay;
|
||||
WSAEVENT client_event;
|
||||
WSAEVENT server_event;
|
||||
char* send_buf;
|
||||
size_t* send_buf_count;
|
||||
char* recv_buf;
|
||||
size_t* recv_buf_count;
|
||||
uint field_0x40;
|
||||
SOCKADDR client_addr;
|
||||
int field_0x54;
|
||||
int field_0x58;
|
||||
} pcpt_t;
|
||||
|
||||
e_pcpt_t pcptInitStream(pcpt_t* sock);
|
||||
void pcptClose(pcpt_t* sock);
|
||||
void pcptCloseDataSock(pcpt_t* sock);
|
||||
e_pcpt_t pcptAcceptServer(pcpt_t* stream, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptCheckConnectAble(pcpt_t* sock, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask);
|
||||
e_pcpt_t pcptIsBusy(pcpt_t* sock, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptOpenDataSockServer(pcpt_t* sock, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptOpenServer(pcpt_t* sock, int open_mode, ushort port);
|
||||
e_pcpt_t pcptRecv(pcpt_t* sock, char* recv_buf, size_t* recv_buf_len, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptSend(pcpt_t* sock, char* send_buf, size_t* send_len, uint param_4, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptSendAllMsg(pcpt_t* sock, timeout_t timeout_ms);
|
||||
void pcptSetConfig(pcpt_t* sock, uint config, uint value);
|
||||
#include "pcp.h"
|
||||
|
||||
typedef enum e_pcpt {
|
||||
e_pcpt_ok = 0,
|
||||
e_pcpt_to = 1,
|
||||
e_pcpt_closed = 2,
|
||||
e_pcpt_no_client = 3,
|
||||
|
||||
e_pcpt_not_open = -1,
|
||||
// TODO: Check if these two are the wrong way round!
|
||||
e_pcpt_already_open = -2,
|
||||
e_pcpt_already_connected = -3,
|
||||
e_pcpt_pointer_unset = -4,
|
||||
|
||||
e_pcpt_cannot_open = -8,
|
||||
e_pcpt_nobufs = -9,
|
||||
e_pcpt_wsa2_generic = -10,
|
||||
e_pcpt_inval_addr = -12,
|
||||
|
||||
e_pcpt_NO_IDEA_WHAT_THIS_IS = -13,
|
||||
|
||||
e_pcpt_recv_unset = -15,
|
||||
e_pcpt_wsa_noinit = -16,
|
||||
e_pcpt_unknown = -17,
|
||||
} e_pcpt_t;
|
||||
|
||||
e_pcpt_t _pcptGetErrorFromWin(int err);
|
||||
#define _errW2T(err) _pcptGetErrorFromWin(err)
|
||||
|
||||
typedef struct pcpt {
|
||||
SOCKET server_sock;
|
||||
SOCKET client_sock;
|
||||
int client_open;
|
||||
int open;
|
||||
e_pcpt_t err;
|
||||
uint field_0x14;
|
||||
uint config_0;
|
||||
uint config_1;
|
||||
uint so_linger;
|
||||
uint tcp_nodelay;
|
||||
WSAEVENT client_event;
|
||||
WSAEVENT server_event;
|
||||
unsigned char* send_buf;
|
||||
size_t* send_buf_count;
|
||||
unsigned char* recv_buf;
|
||||
size_t* recv_buf_count;
|
||||
uint field_0x40;
|
||||
SOCKADDR client_addr;
|
||||
int field_0x54;
|
||||
int field_0x58;
|
||||
} pcpt_t;
|
||||
|
||||
e_pcpt_t pcptInitStream(pcpt_t* sock);
|
||||
void pcptClose(pcpt_t* sock);
|
||||
void pcptCloseDataSock(pcpt_t* sock);
|
||||
e_pcpt_t pcptAcceptServer(pcpt_t* stream, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptCheckConnectAble(pcpt_t* sock, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask);
|
||||
e_pcpt_t pcptIsBusy(pcpt_t* sock, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptOpenDataSockServer(pcpt_t* sock, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptOpenServer(pcpt_t* sock, int open_mode, ushort port);
|
||||
e_pcpt_t pcptRecv(pcpt_t* sock, unsigned char* recv_buf, size_t* recv_buf_len, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptSend(pcpt_t* sock, unsigned char* send_buf, size_t* send_len, uint param_4, timeout_t timeout_ms);
|
||||
e_pcpt_t pcptSendAllMsg(pcpt_t* sock, timeout_t timeout_ms);
|
||||
void pcptSetConfig(pcpt_t* sock, uint config, uint value);
|
||||
|
87
src/micetools/lib/libpcp/util.c
Normal file
87
src/micetools/lib/libpcp/util.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include "pcpa.h"
|
||||
|
||||
void pcptPrint(pcpt_t* stream, char* name) {
|
||||
printf(" PCPT %s STATUS\n", name);
|
||||
printf(" Current errno: %d\n", stream->err);
|
||||
printf(" Server socket: %08X (%d)\n", stream->server_sock, stream->open);
|
||||
printf(" Client socket: %08X (%d)\n", stream->client_sock, stream->client_open);
|
||||
if (stream->send_buf)
|
||||
printf(" Send buffer: %.*s\n", *stream->send_buf_count, stream->send_buf);
|
||||
else
|
||||
puts(" Send buffer: -");
|
||||
if (stream->recv_buf)
|
||||
printf(" Recv buffer: %.*s\n", *stream->recv_buf_count, stream->recv_buf);
|
||||
else
|
||||
puts(" Recv buffer: -");
|
||||
}
|
||||
|
||||
void pcppPrint(pcpp_t* stream) {
|
||||
puts("PCPP STATUS");
|
||||
printf(" Current errno: %d state: %d\n", stream->err, stream->state);
|
||||
printf(" Open: %d at %d\n", stream->open, stream->last_active);
|
||||
printf(" Read buf: %.*s\n", stream->read_bytes_num, stream->read_bytes_buf);
|
||||
printf(" Send buf: %.*s\n", stream->send_buf_len, stream->send_buf);
|
||||
printf(" Send binary: %p (%d[?])\n", stream->send_binary_buf, stream->field_0x1f8);
|
||||
printf(" Recv binary: %p (%d)\n", stream->recv_binary_buf, stream->recv_binary_buf_len);
|
||||
|
||||
pcptPrint(&stream->sock, "TEXT");
|
||||
pcptPrint(&stream->data_sock, "BINARY");
|
||||
}
|
||||
|
||||
void pcpaPrint(pcpa_t* stream) {
|
||||
puts("PCPA STATUS");
|
||||
amtime_t now;
|
||||
amiTimerGet(&now);
|
||||
printf("Now: %d\n", _amTimeMs(now));
|
||||
|
||||
printf("Current errno: %d\n", stream->err);
|
||||
printf("%d/%d callbacks registered at %p\n", stream->callback_count, stream->callback_max, stream->callback_table);
|
||||
printf("Binary mode: %d (%p/%p)\n", stream->binary_mode, stream->binary_mode_before_cb,
|
||||
stream->binary_mode_after_cb);
|
||||
|
||||
if (stream->recv_buffer)
|
||||
printf("Recv buffer: %.*s\n", stream->recv_buffer_len, stream->recv_buffer);
|
||||
else
|
||||
puts("Recv buffer: -");
|
||||
if (stream->send_buffer)
|
||||
printf("Send buffer: %.*s\n", stream->send_buffer_len, stream->send_buffer);
|
||||
else
|
||||
puts("Send buffer: -");
|
||||
|
||||
pcppPrint(&stream->pcpp);
|
||||
|
||||
printf("Send data: %.*s\n", stream->send_data.length, stream->send_data.data);
|
||||
|
||||
puts("Parse data:");
|
||||
printf(" %d commands:\n", stream->recv_data.cmd_count);
|
||||
for (size_t i = 0; i < stream->recv_data.cmd_count; i++) {
|
||||
byte kwd = stream->recv_data.keywords[i];
|
||||
if (kwd != 0) kwd++;
|
||||
printf(" & %02d '%s'\n", kwd, stream->recv_data.strings + kwd);
|
||||
byte value = stream->recv_data.values[i];
|
||||
if (value != 0) value++;
|
||||
printf(" = %02d '%s'\n", value, stream->recv_data.strings + value);
|
||||
if (stream->recv_data.strings[kwd] == 0) break;
|
||||
}
|
||||
puts(" Raw strings table:");
|
||||
for (size_t i = 0; i < PCP_BUF_MAX; i = i + 32) {
|
||||
printf(" ");
|
||||
for (size_t j = i; j < i + 32; j++) {
|
||||
printf("%02X ", stream->recv_data.strings[j]);
|
||||
if (j % 16 == 15)
|
||||
printf(" ");
|
||||
else if (j % 8 == 7)
|
||||
printf(" ");
|
||||
}
|
||||
printf(" ");
|
||||
for (size_t j = i; j < i + 32; j++) {
|
||||
char chr = stream->recv_data.strings[j];
|
||||
if (' ' <= chr && chr <= '~')
|
||||
printf("%c", chr);
|
||||
else
|
||||
printf(".");
|
||||
if (j % 16 == 15) printf(" ");
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
}
|
@ -1,16 +1,8 @@
|
||||
subdir('util') # This is the only lib that should ever be link_with'd by another lib
|
||||
subdir('json')
|
||||
subdir('am')
|
||||
subdir('dmi')
|
||||
subdir('mice')
|
||||
|
||||
fs = import('fs')
|
||||
# Handle the fact we aren't distributing the libpcp source
|
||||
if fs.exists('libpcp/libpcp.c')
|
||||
subdir('libpcp')
|
||||
libpcp_is_static = true
|
||||
else
|
||||
libpcp = meson.get_compiler('c').find_library('libpcp', dirs: libs_dir, required: false)
|
||||
assert(libpcp.found(), 'Unable to locate libpcp.lib. Make sure to place it in the src/ folder prior to building.')
|
||||
libpcp_is_static = false
|
||||
endif
|
||||
subdir('util') # This is the only lib that should ever be link_with'd by another lib
|
||||
subdir('json')
|
||||
subdir('dmi')
|
||||
subdir('mice')
|
||||
subdir('am')
|
||||
|
||||
fs = import('fs')
|
||||
subdir('libpcp')
|
||||
|
@ -1,122 +1,129 @@
|
||||
#include "exe.h"
|
||||
|
||||
bool inject_debug_wait(HANDLE process) {
|
||||
BOOL present;
|
||||
|
||||
fprintf(stderr, "Waiting for debugger to attach.\n");
|
||||
do {
|
||||
Sleep(1000);
|
||||
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
||||
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
} while (!present);
|
||||
fprintf(stderr, "Debugger attached, resuming\n");
|
||||
return true;
|
||||
}
|
||||
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
|
||||
int nchars = strlen(argument);
|
||||
|
||||
LPVOID arg_addr = VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (arg_addr == NULL) {
|
||||
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
|
||||
fprintf(stderr, "Fatal: WriteProcessMemory failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE remote_thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
|
||||
if (remote_thread == NULL) {
|
||||
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
|
||||
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD result;
|
||||
if (FAILED(GetExitCodeThread(remote_thread, &result))) {
|
||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
if (result == 0) {
|
||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool inject_dll(HANDLE process, LPCSTR inject) {
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32 == NULL) {
|
||||
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
|
||||
if (addr_LoadLibraryA == NULL) {
|
||||
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return remote_call(process, addr_LoadLibraryA, inject);
|
||||
}
|
||||
|
||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
|
||||
STARTUPINFOA startupInfo;
|
||||
PROCESS_INFORMATION processInformation;
|
||||
|
||||
memset(&startupInfo, 0, sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
// char real_inject_path[MAX_PATH + 1];
|
||||
// snprintf(real_inject_path, MAX_PATH + 1, ".\\%s", inject);
|
||||
// GetFullPathNameA(real_inject_path, MAX_PATH + 1, &real_inject_path, NULL);
|
||||
|
||||
// Validate that we're not about to try something insane
|
||||
DWORD found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
|
||||
if (found == 0) {
|
||||
fprintf(stderr, "Fatal: Cannot inject %s: not found: %03x\n", inject, GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
// Start the binary
|
||||
if (FAILED(CreateProcessA(path, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo,
|
||||
&processInformation))) {
|
||||
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (delay) {
|
||||
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
||||
}
|
||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||
|
||||
// Injection completed, let the program continue execution
|
||||
if (FAILED(ResumeThread(processInformation.hThread))) {
|
||||
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
return processInformation.hProcess;
|
||||
|
||||
abort:
|
||||
if (processInformation.hProcess) {
|
||||
if (FAILED(CloseHandle(processInformation.hThread)))
|
||||
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
|
||||
|
||||
if (FAILED(TerminateProcess(processInformation.hProcess, 1)))
|
||||
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
|
||||
}
|
||||
if (processInformation.hThread) {
|
||||
if (FAILED(CloseHandle(processInformation.hThread)))
|
||||
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#include "exe.h"
|
||||
|
||||
bool inject_debug_wait(HANDLE process) {
|
||||
BOOL present;
|
||||
|
||||
fprintf(stderr, "Waiting for debugger to attach.\n");
|
||||
do {
|
||||
Sleep(1000);
|
||||
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
||||
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
} while (!present);
|
||||
fprintf(stderr, "Debugger attached, resuming\n");
|
||||
return true;
|
||||
}
|
||||
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
|
||||
int nchars = strlen(argument);
|
||||
|
||||
LPVOID arg_addr = VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (arg_addr == NULL) {
|
||||
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
|
||||
fprintf(stderr, "Fatal: WriteProcessMemory failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE remote_thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
|
||||
if (remote_thread == NULL) {
|
||||
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
|
||||
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD result;
|
||||
if (FAILED(GetExitCodeThread(remote_thread, &result))) {
|
||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
if (result == 0) {
|
||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool inject_dll(HANDLE process, LPCSTR inject) {
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32 == NULL) {
|
||||
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
|
||||
if (addr_LoadLibraryA == NULL) {
|
||||
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return remote_call(process, addr_LoadLibraryA, inject);
|
||||
}
|
||||
|
||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
|
||||
STARTUPINFOA startupInfo;
|
||||
PROCESS_INFORMATION processInformation = { 0 };
|
||||
|
||||
memset(&startupInfo, 0, sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
// char real_inject_path[MAX_PATH + 1];
|
||||
// snprintf(real_inject_path, MAX_PATH + 1, ".\\%s", inject);
|
||||
// GetFullPathNameA(real_inject_path, MAX_PATH + 1, &real_inject_path, NULL);
|
||||
|
||||
DWORD found;
|
||||
// Does the exe we're starting exist?
|
||||
found = SearchPathA(NULL, path, NULL, 0, NULL, NULL);
|
||||
if (found == 0) {
|
||||
fprintf(stderr, "Fatal: Cannot start %s: not found\n", path);
|
||||
goto abort;
|
||||
}
|
||||
// Does the DLL we want to inject exist?
|
||||
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
|
||||
if (found == 0) {
|
||||
fprintf(stderr, "Fatal: Cannot inject %s: not found\n", inject);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
// Start the binary
|
||||
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo,
|
||||
&processInformation)) {
|
||||
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (delay) {
|
||||
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
||||
}
|
||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||
|
||||
// Injection completed, let the program continue execution
|
||||
if (FAILED(ResumeThread(processInformation.hThread))) {
|
||||
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
return processInformation.hProcess;
|
||||
|
||||
abort:
|
||||
if (processInformation.hProcess) {
|
||||
if (!CloseHandle(processInformation.hThread))
|
||||
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
|
||||
|
||||
if (!TerminateProcess(processInformation.hProcess, 1))
|
||||
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
|
||||
}
|
||||
if (processInformation.hThread) {
|
||||
if (!CloseHandle(processInformation.hThread))
|
||||
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
|
||||
}
|
||||
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
@ -1,56 +1,69 @@
|
||||
#include <winioctl.h>
|
||||
|
||||
#define FILE_DEVICE_SEGA 0x9c40
|
||||
|
||||
// amSramInit
|
||||
#define IOCTL_MXSRAM_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amSramInit
|
||||
#define IOCTL_MXSRAM_GET_SECTOR_SIZE CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXSRAM_GET_VERSION CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
// EEPROM uses MXSMBUS_GUID device class
|
||||
// DIPSW uses MXSMBUS_GUID device class
|
||||
// Platform uses PLATFORM_GUID device class
|
||||
|
||||
// amDipswRequestReadByteInternal
|
||||
// amDipswReadByteInternal
|
||||
// amDipswWriteByteInternal
|
||||
// /\ all either use SUPERIO or SMBUS. Which is unknown atm. All use 0x801
|
||||
//
|
||||
// amDipswGetDriverVersion
|
||||
// /\ uses either SUPERIO or SMBUS. Which is unknown atm. Uses 0x802
|
||||
|
||||
// Same as IOCTL_MXSRAM_PING
|
||||
// amHmProbeSuperIoDevice
|
||||
#define IOCTL_MXSUPERIO_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amHmGetLPCChipId
|
||||
#define IOCTL_MXSUPERIO_READ CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_MXSUPERIO_UNKNOWN CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
// amHmLpcReadByte
|
||||
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_READ CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
// amHmLpcWriteByte
|
||||
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
|
||||
#define IOCTL_MXJVS_EXCHANGE CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
// Same as IOCTL_MXSUPERIO_READ
|
||||
// amHmI2CReadByte,amHmI2CWriteByte,amEepromWait
|
||||
#define IOCTL_MXSMBUS_REQUEST CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
// amEepromGetDriverVerision
|
||||
#define IOCTL_MXSMBUS_GET_VERSION CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amEepromI2CReadBlock,amEepromI2CWriteBlock,amHmGetLPCChipId
|
||||
#define IOCTL_MXSMBUS_I2C CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_MXSMBUS_IDK CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
#define IOCTL_COLUMBA_READ_DMI CTL_CODE(FILE_DEVICE_SEGA, 0x841, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
#define IOCTL_MXHWRESET_RESET CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_MXPARALLEL_WRITE_DATA CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_DATA CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_STATUS CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_STATUS CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_CTRL_PORT CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_CTRL_PORT CTL_CODE(FILE_DEVICE_SEGA, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_FLAGS CTL_CODE(FILE_DEVICE_SEGA, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_FLAGS CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#include <winioctl.h>
|
||||
|
||||
#define FILE_DEVICE_SEGA 0x9c40
|
||||
|
||||
// amSramInit
|
||||
#define IOCTL_MXSRAM_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amSramInit
|
||||
#define IOCTL_MXSRAM_GET_SECTOR_SIZE \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXSRAM_GET_VERSION \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
// EEPROM uses MXSMBUS_GUID device class
|
||||
// DIPSW uses MXSMBUS_GUID device class
|
||||
// Platform uses PLATFORM_GUID device class
|
||||
|
||||
// amDipswRequestReadByteInternal
|
||||
// amDipswReadByteInternal
|
||||
// amDipswWriteByteInternal
|
||||
// /\ all either use SUPERIO or SMBUS. Which is unknown atm. All use 0x801
|
||||
//
|
||||
// amDipswGetDriverVersion
|
||||
// /\ uses either SUPERIO or SMBUS. Which is unknown atm. Uses 0x802
|
||||
|
||||
// Same as IOCTL_MXSRAM_PING
|
||||
// amHmProbeSuperIoDevice
|
||||
#define IOCTL_MXSUPERIO_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amHmGetLPCChipId
|
||||
#define IOCTL_MXSUPERIO_READ CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_MXSUPERIO_WRITE CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
// amHmLpcReadByte
|
||||
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_READ \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
// amHmLpcWriteByte
|
||||
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
|
||||
#define IOCTL_MXJVS_EXCHANGE CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
// Same as IOCTL_MXSUPERIO_READ
|
||||
// amHmI2CReadByte,amHmI2CWriteByte,amEepromWait
|
||||
#define IOCTL_MXSMBUS_REQUEST CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
// amEepromGetDriverVerision
|
||||
#define IOCTL_MXSMBUS_GET_VERSION \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amEepromI2CReadBlock,amEepromI2CWriteBlock,amHmGetLPCChipId
|
||||
#define IOCTL_MXSMBUS_I2C CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_MXSMBUS_IDK CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
#define IOCTL_COLUMBA_READ CTL_CODE(FILE_DEVICE_SEGA, 0x841, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
#define IOCTL_MXHWRESET_RESET CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_MXPARALLEL_WRITE_DATA \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_DATA \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_STATUS \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_STATUS \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_CTRL_PORT \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_CTRL_PORT \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_FLAGS \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_FLAGS \
|
||||
CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
@ -1,228 +1,228 @@
|
||||
#include "patch.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool fetch(json_value* object, char* name, json_value** value) {
|
||||
if (object->type != json_object) return false;
|
||||
for (size_t j = 0; j < object->u.object.length; j++) {
|
||||
json_object_entry* entry = &(object->u.object.values[j]);
|
||||
if (strncmp(name, entry->name, entry->name_length) == 0) {
|
||||
*value = entry->value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool fetch_string(json_value* object, char* name, char** value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_string) return false;
|
||||
*value = fetched->u.string.ptr;
|
||||
return true;
|
||||
}
|
||||
bool fetch_int(json_value* object, char* name, size_t* value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_integer) return false;
|
||||
*value = fetched->u.integer;
|
||||
return true;
|
||||
}
|
||||
bool fetch_bool(json_value* object, char* name, bool* value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_boolean) return false;
|
||||
*value = fetched->u.boolean;
|
||||
return true;
|
||||
}
|
||||
void free_patches(patches_t* patches) {
|
||||
if (patches->nopatchsets == 0) return;
|
||||
for (int i = patches->nopatchsets - 1; i >= 0; i--) {
|
||||
if (patches->patchsets[i] != NULL) {
|
||||
for (int j = 0; j < patches->patchsets[i]->nopatches; j++) {
|
||||
if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from);
|
||||
if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to);
|
||||
}
|
||||
free(patches->patchsets[i]);
|
||||
}
|
||||
}
|
||||
patches->nopatchsets = 0;
|
||||
}
|
||||
|
||||
json_value* load_json_from_file(char* path, char* error) {
|
||||
FILE* fp;
|
||||
fopen_s(&fp, path, "r");
|
||||
if (fp == NULL) {
|
||||
if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t sz = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char* json_buf = (char*)malloc(sz);
|
||||
if (json_buf == NULL) {
|
||||
if (error != NULL) snprintf(error, json_error_max, "Failed to allocate file buffer");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
if (!(sz = fread(json_buf, 1, sz, fp))) {
|
||||
if (error != NULL) snprintf(error, json_error_max, "Failed to read file");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
};
|
||||
fclose(fp);
|
||||
|
||||
json_settings settings = { 0 };
|
||||
return json_parse_ex(&settings, json_buf, sz, error);
|
||||
}
|
||||
|
||||
bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) {
|
||||
patches->nopatchsets = set_count;
|
||||
patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*));
|
||||
for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL;
|
||||
|
||||
error[0] = '\0';
|
||||
for (int i = 0; i < set_count; i++) {
|
||||
patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t));
|
||||
patches->patchsets[i] = patchset;
|
||||
patchset->name = NULL;
|
||||
patchset->description = NULL;
|
||||
patchset->binary_name = NULL;
|
||||
patchset->apply = false;
|
||||
patchset->nopatches = 0;
|
||||
|
||||
char *name, *description, *binary_name;
|
||||
if (!fetch_string(set_json[i], "name", &name)) {
|
||||
snprintf(error, json_error_max, "'name' missing for patch %d", i);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(set_json[i], "description", &description)) {
|
||||
snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(set_json[i], "binary_name", &binary_name)) binary_name = NULL;
|
||||
|
||||
bool apply;
|
||||
if (!fetch_bool(set_json[i], "apply", &apply)) {
|
||||
snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
json_value* set_patches;
|
||||
if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) {
|
||||
char* patches_file_path;
|
||||
if (fetch_string(set_json[i], "patches_file", &patches_file_path)) {
|
||||
char load_error[json_error_max];
|
||||
set_patches = load_json_from_file(patches_file_path, load_error);
|
||||
if (set_patches == NULL) {
|
||||
fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", patches_file_path, load_error);
|
||||
continue;
|
||||
}
|
||||
if (set_patches->type != json_array) {
|
||||
fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", patches_file_path);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
snprintf(error, json_error_max, "Neither 'patches' nor 'patchs_file' in patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
int count = set_patches->u.array.length;
|
||||
patchset = (patchset_t*)realloc(patchset, sizeof(patchset_t) + (sizeof(patch_t) * count));
|
||||
patches->patchsets[i] = patchset;
|
||||
|
||||
patchset->name = name;
|
||||
patchset->description = description;
|
||||
patchset->binary_name = binary_name;
|
||||
patchset->apply = apply;
|
||||
patchset->nopatches = count;
|
||||
memset(patchset->patches, 0, count * (sizeof(patch_t)));
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
json_value* this_patch = set_patches->u.array.values[j];
|
||||
size_t at;
|
||||
char *from, *to;
|
||||
if (!fetch_int(this_patch, "at", &at)) {
|
||||
char* at_str;
|
||||
if (!fetch_string(this_patch, "at", &at_str)) {
|
||||
snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (strlen(at_str) > 8) {
|
||||
snprintf(error, json_error_max, "invalid 'at' value for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
hex_to_bin(at_str, (void*)&at, 8);
|
||||
at = _byteswap_ulong(at); // Endianess!
|
||||
}
|
||||
if (!fetch_string(this_patch, "from", &from)) {
|
||||
snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(this_patch, "to", &to)) {
|
||||
snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
char* patch_name;
|
||||
if (!fetch_string(this_patch, "name", &patch_name)) patch_name = NULL;
|
||||
|
||||
patchset->patches[j].name = patch_name;
|
||||
patchset->patches[j].offset = at;
|
||||
size_t size = strlen(from);
|
||||
if (size != strlen(to)) {
|
||||
snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (size % 2 != 0) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
char* bin_from = patchset->patches[j].from = (char*)malloc(size / 2);
|
||||
char* bin_to = patchset->patches[j].to = (char*)malloc(size / 2);
|
||||
if (!hex_to_bin(from, bin_from, size)) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j);
|
||||
goto failed;
|
||||
};
|
||||
if (!hex_to_bin(to, bin_to, size)) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j);
|
||||
goto failed;
|
||||
};
|
||||
|
||||
patchset->patches[j].count = size / 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
free_patches(patches);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load_patches(patches_t* patches, char* path, char* error) {
|
||||
patches->nopatchsets = 0;
|
||||
|
||||
json_value* parsed = load_json_from_file(path, error);
|
||||
if (parsed == NULL) return false;
|
||||
|
||||
int loaded_patches = 0;
|
||||
json_value** patches_json;
|
||||
if (parsed->type == json_array) {
|
||||
loaded_patches = parsed->u.array.length;
|
||||
patches_json = parsed->u.array.values;
|
||||
} else if (parsed->type == json_object) {
|
||||
loaded_patches = 1;
|
||||
patches_json = &parsed;
|
||||
} else {
|
||||
snprintf(error, json_error_max, "Patch file format error");
|
||||
json_value_free(parsed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_patches(patches, patches_json, loaded_patches, error)) return false;
|
||||
return true;
|
||||
}
|
||||
#include "patch.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool fetch(json_value* object, char* name, json_value** value) {
|
||||
if (object->type != json_object) return false;
|
||||
for (size_t j = 0; j < object->u.object.length; j++) {
|
||||
json_object_entry* entry = &(object->u.object.values[j]);
|
||||
if (strncmp(name, entry->name, entry->name_length) == 0) {
|
||||
*value = entry->value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool fetch_string(json_value* object, char* name, char** value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_string) return false;
|
||||
*value = fetched->u.string.ptr;
|
||||
return true;
|
||||
}
|
||||
bool fetch_int(json_value* object, char* name, size_t* value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_integer) return false;
|
||||
*value = (size_t)fetched->u.integer;
|
||||
return true;
|
||||
}
|
||||
bool fetch_bool(json_value* object, char* name, bool* value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_boolean) return false;
|
||||
*value = fetched->u.boolean;
|
||||
return true;
|
||||
}
|
||||
void free_patches(patches_t* patches) {
|
||||
if (patches->nopatchsets == 0) return;
|
||||
for (int i = patches->nopatchsets - 1; i >= 0; i--) {
|
||||
if (patches->patchsets[i] != NULL) {
|
||||
for (size_t j = 0; j < patches->patchsets[i]->nopatches; j++) {
|
||||
if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from);
|
||||
if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to);
|
||||
}
|
||||
free(patches->patchsets[i]);
|
||||
}
|
||||
}
|
||||
patches->nopatchsets = 0;
|
||||
}
|
||||
|
||||
json_value* load_json_from_file(char* path, char* error) {
|
||||
FILE* fp;
|
||||
fopen_s(&fp, path, "r");
|
||||
if (fp == NULL) {
|
||||
if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t sz = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char* json_buf = (char*)malloc(sz);
|
||||
if (json_buf == NULL) {
|
||||
if (error != NULL) snprintf(error, json_error_max, "Failed to allocate file buffer");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
if (!(sz = fread(json_buf, 1, sz, fp))) {
|
||||
if (error != NULL) snprintf(error, json_error_max, "Failed to read file");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
};
|
||||
fclose(fp);
|
||||
|
||||
json_settings settings = { 0 };
|
||||
return json_parse_ex(&settings, json_buf, sz, error);
|
||||
}
|
||||
|
||||
bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) {
|
||||
patches->nopatchsets = set_count;
|
||||
patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*));
|
||||
for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL;
|
||||
|
||||
error[0] = '\0';
|
||||
for (int i = 0; i < set_count; i++) {
|
||||
patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t));
|
||||
patches->patchsets[i] = patchset;
|
||||
patchset->name = NULL;
|
||||
patchset->description = NULL;
|
||||
patchset->binary_name = NULL;
|
||||
patchset->apply = false;
|
||||
patchset->nopatches = 0;
|
||||
|
||||
char *name, *description, *binary_name;
|
||||
if (!fetch_string(set_json[i], "name", &name)) {
|
||||
snprintf(error, json_error_max, "'name' missing for patch %d", i);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(set_json[i], "description", &description)) {
|
||||
snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(set_json[i], "binary_name", &binary_name)) binary_name = NULL;
|
||||
|
||||
bool apply;
|
||||
if (!fetch_bool(set_json[i], "apply", &apply)) {
|
||||
snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
json_value* set_patches;
|
||||
if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) {
|
||||
char* patches_file_path;
|
||||
if (fetch_string(set_json[i], "patches_file", &patches_file_path)) {
|
||||
char load_error[json_error_max];
|
||||
set_patches = load_json_from_file(patches_file_path, load_error);
|
||||
if (set_patches == NULL) {
|
||||
fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", patches_file_path, load_error);
|
||||
continue;
|
||||
}
|
||||
if (set_patches->type != json_array) {
|
||||
fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", patches_file_path);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
snprintf(error, json_error_max, "Neither 'patches' nor 'patchs_file' in patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
int count = set_patches->u.array.length;
|
||||
patchset = (patchset_t*)realloc(patchset, sizeof(patchset_t) + (sizeof(patch_t) * count));
|
||||
patches->patchsets[i] = patchset;
|
||||
|
||||
patchset->name = name;
|
||||
patchset->description = description;
|
||||
patchset->binary_name = binary_name;
|
||||
patchset->apply = apply;
|
||||
patchset->nopatches = count;
|
||||
memset(patchset->patches, 0, count * (sizeof(patch_t)));
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
json_value* this_patch = set_patches->u.array.values[j];
|
||||
size_t at;
|
||||
char *from, *to;
|
||||
if (!fetch_int(this_patch, "at", &at)) {
|
||||
char* at_str;
|
||||
if (!fetch_string(this_patch, "at", &at_str)) {
|
||||
snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (strlen(at_str) > 8) {
|
||||
snprintf(error, json_error_max, "invalid 'at' value for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
hex_to_bin(at_str, (void*)&at, 8);
|
||||
at = _byteswap_ulong(at); // Endianess!
|
||||
}
|
||||
if (!fetch_string(this_patch, "from", &from)) {
|
||||
snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(this_patch, "to", &to)) {
|
||||
snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
char* patch_name;
|
||||
if (!fetch_string(this_patch, "name", &patch_name)) patch_name = NULL;
|
||||
|
||||
patchset->patches[j].name = patch_name;
|
||||
patchset->patches[j].offset = at;
|
||||
size_t size = strlen(from);
|
||||
if (size != strlen(to)) {
|
||||
snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (size % 2 != 0) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
unsigned char* bin_from = patchset->patches[j].from = (unsigned char*)malloc(size / 2);
|
||||
unsigned char* bin_to = patchset->patches[j].to = (unsigned char*)malloc(size / 2);
|
||||
if (!hex_to_bin(from, bin_from, size)) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j);
|
||||
goto failed;
|
||||
};
|
||||
if (!hex_to_bin(to, bin_to, size)) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j);
|
||||
goto failed;
|
||||
};
|
||||
|
||||
patchset->patches[j].count = size / 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
free_patches(patches);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load_patches(patches_t* patches, char* path, char* error) {
|
||||
patches->nopatchsets = 0;
|
||||
|
||||
json_value* parsed = load_json_from_file(path, error);
|
||||
if (parsed == NULL) return false;
|
||||
|
||||
int loaded_patches = 0;
|
||||
json_value** patches_json;
|
||||
if (parsed->type == json_array) {
|
||||
loaded_patches = parsed->u.array.length;
|
||||
patches_json = parsed->u.array.values;
|
||||
} else if (parsed->type == json_object) {
|
||||
loaded_patches = 1;
|
||||
patches_json = &parsed;
|
||||
} else {
|
||||
snprintf(error, json_error_max, "Patch file format error");
|
||||
json_value_free(parsed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_patches(patches, patches_json, loaded_patches, error)) return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
subdir('lib')
|
||||
|
||||
subdir('micepatch')
|
||||
subdir('micekeychip')
|
||||
subdir('launcher')
|
||||
subdir('dll')
|
||||
|
||||
subdir('micetest')
|
||||
subdir('lib')
|
||||
|
||||
subdir('micepatch')
|
||||
subdir('micekeychip')
|
||||
subdir('launcher')
|
||||
subdir('dll')
|
||||
subdir('miceboot')
|
||||
subdir('util')
|
||||
|
4
src/micetools/miceboot/TrueCrypt.cmd
Normal file
4
src/micetools/miceboot/TrueCrypt.cmd
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
@REM "C:\Program Files (x86)\TrueCrypt\TrueCrypt.exe" %*
|
||||
echo %*
|
||||
pause
|
150
src/micetools/miceboot/ewfapi.h
Normal file
150
src/micetools/miceboot/ewfapi.h
Normal file
@ -0,0 +1,150 @@
|
||||
/****************************************************************************
|
||||
|
||||
Copyright (c) 2003 Microsoft Corporation
|
||||
Module Name: ewfapi.h
|
||||
Abstract: Defines the EWF APIs
|
||||
Environment: User mode
|
||||
Revision History:
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __EWFAPI_H__
|
||||
#define __EWFAPI_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef EWFIMP
|
||||
#define EWFIMP __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
typedef struct _EWF_VOLUME_NAME_ENTRY {
|
||||
struct _EWF_VOLUME_NAME_ENTRY* Next;
|
||||
WCHAR Name[1];
|
||||
} EWF_VOLUME_NAME_ENTRY, *PEWF_VOLUME_NAME_ENTRY;
|
||||
|
||||
typedef enum {
|
||||
EWF_NO_CMD = 0, // no pending command
|
||||
EWF_ENABLE, // overlay will be enabled
|
||||
EWF_DISABLE, // overlay will be disabled
|
||||
EWF_SET_LEVEL, // overlay level will be set
|
||||
EWF_COMMIT // current level will be committed to the protected volume
|
||||
} EWF_CMD;
|
||||
|
||||
typedef enum {
|
||||
EWF_ENABLED, // The overlay is enabled on the volume
|
||||
EWF_DISABLED // The overlay is disabled on the volume
|
||||
} EWF_STATE;
|
||||
|
||||
typedef enum {
|
||||
EWF_DISK, // DISK overlay
|
||||
EWF_RAM, // RAM overlay, with an associated overlay volume store
|
||||
EWF_RAM_REG, // RAM overlay, without an associated overlay volume store
|
||||
} EWF_TYPE,
|
||||
*PEWF_TYPE;
|
||||
|
||||
#define EWF_MAX_DEVICE_NAME_LENGTH (256)
|
||||
#define EWF_VOLUME_ID_SIZE (16)
|
||||
|
||||
typedef struct _EWF_VOLUME_DESC {
|
||||
WCHAR DeviceName[EWF_MAX_DEVICE_NAME_LENGTH]; // Device name of the volume
|
||||
UCHAR VolumeID[EWF_VOLUME_ID_SIZE]; // 16 byte volume identifier
|
||||
} EWF_VOLUME_DESC, *PEWF_VOLUME_DESC;
|
||||
|
||||
//
|
||||
// This is a variable size structure depending on how many protected overlay
|
||||
// volumes there are.
|
||||
//
|
||||
typedef struct _EWF_OVERLAY_STORE_CONFIG {
|
||||
ULONG FormatVersion; // Version of Overlay-Store format
|
||||
LONGLONG VolumeSize; // Size of the overlay volume in bytes
|
||||
|
||||
ULONG NumSegments; // Number of segments that the volume is divided into
|
||||
ULONG FreeSegments; // Number of segments that are free
|
||||
ULONG SegmentSize; // Size of each segment in bytes
|
||||
|
||||
ULONG MaxVolumes; // Maximum number of protected volumes
|
||||
ULONG NumVolumes; // Number of currently protected volumes
|
||||
USHORT MaxLevels; // Maximum number of overlay levels
|
||||
EWF_VOLUME_DESC VolumeDescArray[1];
|
||||
// The array holds NumVolume count volume descriptions
|
||||
} EWF_OVERLAY_STORE_CONFIG, *PEWF_OVERLAY_STORE_CONFIG;
|
||||
|
||||
typedef struct _EWF_COMMAND {
|
||||
EWF_CMD Command; // ENABLE, DISABLE, etc..
|
||||
ULONG Param1; // command first parameter.
|
||||
ULONG Param2; // command second parameter.
|
||||
|
||||
} EWF_COMMAND, *PEWF_COMMAND;
|
||||
|
||||
#define EWF_MAX_LEVEL_NAME_LENGTH (64)
|
||||
|
||||
typedef struct _EWF_LEVEL_DESC {
|
||||
WCHAR LevelName[EWF_MAX_LEVEL_NAME_LENGTH];
|
||||
// friendly name of the level
|
||||
// If the length is equal to EWF_MAX_LEVEL_NAME_LENGTH
|
||||
// then no null terminator is stored.
|
||||
FILETIME LevelEndTime; // time at which the level was ended
|
||||
LONGLONG LevelDataSize; // Size of the data in the level in bytes
|
||||
} EWF_LEVEL_DESC, *PEWF_LEVEL_DESC;
|
||||
|
||||
#define EWF_MAX_PERSISTENT_DATA (32) // maximum number of bytes that can be persisted
|
||||
|
||||
typedef struct _EWF_VOLUME_CONFIG {
|
||||
EWF_TYPE Type; // Type of overlay for this volume
|
||||
EWF_STATE State; // state of the overlay for this volume, ENABLED or DISABLED
|
||||
EWF_COMMAND BootCommand; // Command to execute on next restart
|
||||
|
||||
// Small amount of persistent data that survives a restore
|
||||
UCHAR PersistentData[EWF_MAX_PERSISTENT_DATA];
|
||||
|
||||
USHORT MaxLevels; // Maximum number of checkpoint levels for this volume
|
||||
ULONG ClumpSize; // 512 bytes
|
||||
USHORT CurrentLevel; // Current checkpoint level
|
||||
|
||||
union {
|
||||
struct {
|
||||
LONGLONG DiskMapSize; // Size of the mapping data on disk
|
||||
LONGLONG DiskDataSize; // Size of the data stored on disk for this protected volume
|
||||
} DiskOverlay;
|
||||
|
||||
struct {
|
||||
LONGLONG RamDataSize; // Size of the data stored in RAM for this protected volume
|
||||
} RamOverlay;
|
||||
};
|
||||
ULONG MemMapSize; // Size of the mapping data in memory
|
||||
EWF_VOLUME_DESC VolumeDesc; // volume device name, and volume ID
|
||||
EWF_LEVEL_DESC LevelDescArray[1]; // Level descripton and end time, and level data size
|
||||
} EWF_VOLUME_CONFIG, *PEWF_VOLUME_CONFIG;
|
||||
|
||||
EWFIMP WCHAR WINAPI EwfMgrGetDriveLetterFromVolumeName(IN LPCWSTR lpVolumeName);
|
||||
EWFIMP BOOL WINAPI EwfMgrVolumeNameListIsEmpty(IN PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
|
||||
EWFIMP VOID WINAPI EwfMgrVolumeNameEntryPop(IN PEWF_VOLUME_NAME_ENTRY* ppVolumeNameList);
|
||||
EWFIMP VOID WINAPI EwfMgrVolumeNameListDelete(IN PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
|
||||
EWFIMP HANDLE WINAPI EwfMgrOpenProtected(IN LPCWSTR lpVolume);
|
||||
EWFIMP BOOL WINAPI EwfMgrClose(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrClearCommand(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrSetPersistentData(IN HANDLE hDevice, IN LPBYTE lpPersistentData, IN DWORD cbPersistentData);
|
||||
EWFIMP BOOL WINAPI EwfMgrGetPersistentData(IN HANDLE hDevice, OUT LPBYTE lpPersistentData, IN DWORD cbPersistentData);
|
||||
EWFIMP BOOL WINAPI EwfMgrCheckpoint(IN HANDLE hDevice, IN OPTIONAL LPCWSTR lpDescription);
|
||||
EWFIMP BOOL WINAPI EwfMgrRestore(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrDisable(IN HANDLE hDevice, IN BOOL fCommit);
|
||||
EWFIMP BOOL WINAPI EwfMgrEnable(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrCommit(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrCommitAndDisableLive(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrCommitFile(IN HANDLE hDevice, IN LPWSTR lpFile);
|
||||
EWFIMP BOOL WINAPI EwfMgrSetLevel(IN HANDLE hDevice, IN OPTIONAL LPCWSTR lpDescription, IN int Level,
|
||||
IN BOOL fDeleteLevel);
|
||||
EWFIMP PEWF_VOLUME_CONFIG WINAPI EwfMgrGetProtectedVolumeConfig(IN HANDLE hDevice);
|
||||
EWFIMP PEWF_VOLUME_NAME_ENTRY WINAPI EwfMgrGetProtectedVolumeList(VOID);
|
||||
EWFIMP HANDLE WINAPI EwfMgrOpenOverlayStore(IN BOOL fOpenForAsyncIO);
|
||||
EWFIMP PEWF_OVERLAY_STORE_CONFIG WINAPI EwfMgrGetOverlayStoreConfig(IN HANDLE hDevice);
|
||||
EWFIMP BOOL WINAPI EwfMgrRegisterLowSpaceNotification(IN HANDLE hDevice, IN LONGLONG FreeBytesRemaining,
|
||||
IN LPOVERLAPPED lpOverlapped);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __EWFAPI_H__
|
31
src/micetools/miceboot/meson.build
Normal file
31
src/micetools/miceboot/meson.build
Normal file
@ -0,0 +1,31 @@
|
||||
executable(
|
||||
'miceprestartup',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'mxprestartup.c',
|
||||
],
|
||||
)
|
||||
|
||||
executable(
|
||||
'micestartup',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'mxstartup.c',
|
||||
],
|
||||
)
|
||||
|
||||
executable(
|
||||
'truecrypt',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'truecrypt.c',
|
||||
],
|
||||
)
|
||||
|
||||
executable(
|
||||
'mxmaster',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'mxmaster.c',
|
||||
],
|
||||
)
|
105
src/micetools/miceboot/mice_ewfapi.h
Normal file
105
src/micetools/miceboot/mice_ewfapi.h
Normal file
@ -0,0 +1,105 @@
|
||||
#include <Windows.h>
|
||||
|
||||
typedef struct __EWF_LEVEL_DESC {
|
||||
WCHAR
|
||||
LevelName[EWF_MAX_LEVEL_NAME_LENGTH];
|
||||
FILETIME
|
||||
LevelEndTime;
|
||||
LONGLONG
|
||||
LevelDataSize;
|
||||
} EWF_LEVEL_DESC, *PEWF_LEVEL_DESC;
|
||||
|
||||
typedef struct _EWF_OVERLAY_STORE_CONFIG {
|
||||
ULONG
|
||||
FormatVersion;
|
||||
LONGLONG
|
||||
VolumeSize;
|
||||
ULONG
|
||||
NumSegments;
|
||||
ULONG
|
||||
FreeSegments;
|
||||
ULONG
|
||||
SegmentSize;
|
||||
ULONG
|
||||
MaxVolumes;
|
||||
ULONG
|
||||
NumVolumes;
|
||||
USHORT
|
||||
MaxLevels;
|
||||
EWF_VOLUME_DESC
|
||||
VolumeDescArray[1];
|
||||
} EWF_OVERLAY_STORE_CONFIG, *PEWF_OVERLAY_STORE_CONFIG;
|
||||
|
||||
typedef struct _EWF_VOLUME_CONFIG {
|
||||
EWF_TYPE
|
||||
Type;
|
||||
EWF_STATE
|
||||
State;
|
||||
EWF_COMMAND
|
||||
BootCommand;
|
||||
UCHAR
|
||||
PersistentData[EWF_MAX_PERSISTENT_DATA];
|
||||
USHORT
|
||||
MaxLevels;
|
||||
ULONG
|
||||
ClumpSize;
|
||||
USHORT
|
||||
CurrentLevel;
|
||||
union {
|
||||
struct {
|
||||
LONGLONG
|
||||
DiskMapSize;
|
||||
LONGLONG
|
||||
DiskDataSize;
|
||||
} DiskOverlay;
|
||||
struct {
|
||||
LONGLONG
|
||||
RamDataSize;
|
||||
} RamOverlay;
|
||||
};
|
||||
ULONG
|
||||
MemMapSize;
|
||||
EWF_VOLUME_DESC
|
||||
VolumeDesc;
|
||||
EWF_LEVEL_DESC
|
||||
LevelDescArray[1];
|
||||
} EWF_VOLUME_CONFIG, *PEWF_VOLUME_CONFIG;
|
||||
|
||||
typedef struct _EWF_VOLUME_DESC {
|
||||
WCHAR _ DeviceName[EWF_MAX_DEVICE_NAME_LENGTH];
|
||||
UCHAR
|
||||
VolumeID[EWF_VOLUME_ID_SIZE];
|
||||
} EWF_VOLUME_DESC, *PEWF_VOLUME_DESC;
|
||||
|
||||
typedef struct _EWF_VOLUME_NAME_ENTRY {
|
||||
struct _EWF_VOLUME_NAME_ENTRY* Next;
|
||||
WCHAR
|
||||
Name[1];
|
||||
} EWF_VOLUME_NAME_ENTRY, *PEWF_VOLUME_NAME_ENTRY;
|
||||
|
||||
HRESULT WINAPI ConfigureEwf(VOID);
|
||||
BOOL EwfMgrActivateHorm(HANDLE hDevice);
|
||||
BOOL EwfMgrCheckpoint(HANDLE hDevice, OPTIONAL LPCWSTR lpDescription);
|
||||
BOOL EwfMgrClearCommand(HANDLE hDevice);
|
||||
BOOL EwfMgrClose(HANDLE hDevice);
|
||||
BOOL EwfMgrCommit(HANDLE hDevice);
|
||||
BOOL WINAPI EwfMgrCommitAndDisableLive(IN HANDLE hDevice, );
|
||||
BOOL WINAPI EwfMgrCommitFile(IN HANDLE hDevice, IN LPWSTR lpFile);
|
||||
BOOL EwfMgrDeactivateHorm(HANDLE hDevice);
|
||||
BOOL EwfMgrDisable(HANDLE hDevice, BOOLfCommit);
|
||||
BOOL EwfMgrEnable(HANDLE hDevice);
|
||||
WCHAR EwfMgrGetDriveLetterFromVolumeName(LPCWSTR lpVolumeName);
|
||||
PEWF_OVERLAY_STORE_CONFIG EwfMgrGetOverlayStoreConfig(HANDLE hDevice);
|
||||
BOOL EwfMgrGetPeristentData(HANDLE hDevice, LPBYTElpPersistentData, DWORDcbPersistentData);
|
||||
PEWF_VOLUME_CONFIG EwfMgrGetProtectedVolumeConfig(HANDLE hDevice);
|
||||
PEWF_VOLUME_NAME_ENTRY EwfMgrGetProtectedVolumeList(VOID);
|
||||
BOOL EwfMgrIsHormActivated(HANDLE hDevice);
|
||||
HANDLE EwfMgrOpenOverlayStore(BOOL fOpenForAsyncIO);
|
||||
HANDLE EwfMgrOpenProtected(LPCWSTR lpVolume);
|
||||
BOOL EwfMgrRegisterLowSpaceNotification(HANDLE hDevice, LONGLONGFreeBytesRemaining, LPOVERLAPPEDlpOverlapped);
|
||||
BOOL EwfMgrRestore(HANDLE hDevice);
|
||||
BOOL EwfMgrSetLevel(HANDLE hDevice, OPTIONAL LPCWSTRlpDescription, intLevel, BOOLfDeleteLevel);
|
||||
BOOL EwfMgrSetPeristentData(HANDLE hDevice, LPBYTE lpPersistentData, DWORD cbPersistentData);
|
||||
VOID EwfMgrVolumeNameEntryPop(PEWF_VOLUME_NAME_ENTRY* ppVolumeNameList);
|
||||
VOID EwfMgrVolumeNameListDelete(PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
|
||||
BOOL EwfMgrVolumeNameListIsEmpty(PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
|
8
src/micetools/miceboot/mxmaster.c
Normal file
8
src/micetools/miceboot/mxmaster.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
puts("mxmaster.exe dummy hit");
|
||||
|
||||
while (1) Sleep(1000);
|
||||
}
|
216
src/micetools/miceboot/mxprestartup.c
Normal file
216
src/micetools/miceboot/mxprestartup.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
Currently unimplemented:
|
||||
- Changing the screen resoltuion to something very small (lol)
|
||||
- The UI that shows "NOW LOADING"
|
||||
*/
|
||||
#include <Windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SYSTEM_USER "SystemUser"
|
||||
#define MXSTARTUP "C:\\System\\Execute\\mxstartup.exe"
|
||||
|
||||
#define RETRIES 100
|
||||
#define STR_INDIR(x) #x
|
||||
#define STR(x) STR_INDIR(x)
|
||||
|
||||
/*
|
||||
|
||||
No debugger:
|
||||
|
||||
153815264b5839090b0d1c1a423c02241633130673071a1e38443912410b47380f213c1d
|
||||
+ 2e0247311e162b666c6640393737724157001f56045b4b4f24333457335a26381f4c3349
|
||||
= 'C:\Windows\System32\wbem\wmitemp.mof'
|
||||
|
||||
270a2a053b29042b261d1b22070d140c (wmitemp.mof)
|
||||
+ 152c05381a141f494a48060223260d29 (key)
|
||||
= '<6/=U=#tpe!$*3!5'
|
||||
|
||||
|
||||
|
||||
Has debugger:
|
||||
|
||||
d0b1c034a32243340505a343659517c121f0319583d205c593a690719604846000e062a6
|
||||
+ 63f10541f0c201c0703022f332a13094b542f130c25491a1c280a65440831296e2563590
|
||||
% 255 (not 256!)
|
||||
= 34a3c57594e444f47535c53797374756d63323c546279667562737c5d68796f6e2379737
|
||||
flip nibbles of each byte
|
||||
= 'C:\\WINDOWS\\system32\\drivers\\mxio.sys'
|
||||
|
||||
9160e5c22392918371e43573f2b095b1 (mxio.sys)
|
||||
+ 43368004f2a34211f4f12120b1b57151
|
||||
% 255
|
||||
= d49666c61636d39466d65693a4660703
|
||||
flip nibbles of each byte
|
||||
= 'Miflac=Ifme9Jfp0'
|
||||
|
||||
*/
|
||||
|
||||
#define PERFECT_RECREATION
|
||||
|
||||
#ifdef PERFECT_RECREATION
|
||||
// C:\Windows\System32\wbem\wmitemp.mof (contains 270a2a053b29042b261d1b22070d140c)
|
||||
// NOTE: On 64 bit windows this is going to be redirected to syswow64
|
||||
#define PATH_NODEBUG_1 "153815264b5839090b0d1c1a423c02241633130673071a1e38443912410b47380f213c1d"
|
||||
#define PATH_NODEBUG_2 "2e0247311e162b666c6640393737724157001f56045b4b4f24333457335a26381f4c3349"
|
||||
|
||||
// C:\WINDOWS\system32\drivers\mxio.sys (contains 9160e5c22392918371e43573f2b095b1)
|
||||
// NOTE: On 64 bit windows this is going to be redirected to syswow64
|
||||
#define PATH_DEBUG_1 "d0b1c034a32243340505a343659517c121f0319583d205c593a690719604846000e062a6"
|
||||
#define PATH_DEBUG_2 "63f10541f0c201c0703022f332a13094b542f130c25491a1c280a65440831296e2563590"
|
||||
|
||||
#define NODEBUG_PSK "152c05381a141f494a48060223260d29"
|
||||
#define DEBUG_PSK "43368004f2a34211f4f12120b1b57151"
|
||||
#else
|
||||
#define PASS_NODEBUG "Miflac=Ifme9Jfp0"
|
||||
#define PASS_DEBUG "<6/=U=#tpe!$*3!5"
|
||||
#endif
|
||||
|
||||
void reboot() {
|
||||
puts("Starting the next hop failed.");
|
||||
puts("We're not going to reboot, but mxprestartup normally would at this point.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char* load_password(const char* path1, const char* path2, const char* psk, bool flip) {
|
||||
char path[37];
|
||||
path[36] = '\0';
|
||||
char temp1[3] = { 0 };
|
||||
char temp2[3] = { 0 };
|
||||
char* pEnd;
|
||||
for (int i = 0; i < 72; i += 2) {
|
||||
temp1[0] = path1[i];
|
||||
temp1[1] = path1[i + 1];
|
||||
temp2[0] = path2[i];
|
||||
temp2[1] = path2[i + 1];
|
||||
uint8_t value = (strtol(temp1, &pEnd, 16) + strtol(temp2, &pEnd, 16)) % 0xff;
|
||||
if (flip)
|
||||
path[i >> 1] = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
|
||||
else
|
||||
path[i >> 1] = value;
|
||||
}
|
||||
|
||||
printf("Attempting to read key from %s\n", path);
|
||||
|
||||
FILE* key_file;
|
||||
fopen_s(&key_file, path, "r");
|
||||
if (!key_file) {
|
||||
printf("! Failed to read file: %d\n", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
char key2[32];
|
||||
fread(key2, 1, 32, key_file);
|
||||
fclose(key_file);
|
||||
|
||||
char* password = malloc(17);
|
||||
password[16] = '\0';
|
||||
|
||||
for (int i = 0; i < 32; i += 2) {
|
||||
temp1[0] = psk[i];
|
||||
temp1[1] = psk[i + 1];
|
||||
temp2[0] = key2[i];
|
||||
temp2[1] = key2[i + 1];
|
||||
uint8_t value = (strtol(temp1, &pEnd, 16) + strtol(temp2, &pEnd, 16)) % 0xff;
|
||||
if (flip)
|
||||
password[i >> 1] = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
|
||||
else
|
||||
password[i >> 1] = value;
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
char* get_password() {
|
||||
if (IsDebuggerPresent()) {
|
||||
#ifdef PERFECT_RECREATION
|
||||
return load_password(PATH_DEBUG_1, PATH_DEBUG_2, DEBUG_PSK, true);
|
||||
#else
|
||||
return PASS_DEBUG;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PERFECT_RECREATION
|
||||
return load_password(PATH_NODEBUG_1, PATH_NODEBUG_2, NODEBUG_PSK, false);
|
||||
#else
|
||||
return PASS_NODEBUG;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc > 4) {
|
||||
puts("Usage:");
|
||||
printf(" %s\n", argv[0]);
|
||||
printf(" %s <mxstartup.exe>\n", argv[0]);
|
||||
printf(" %s <username> <password>\n", argv[0]);
|
||||
printf(" %s <mxstartup.exe> <username> <password>\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
PVOID old = NULL;
|
||||
Wow64DisableWow64FsRedirection(&old);
|
||||
|
||||
BOOL spawned = FALSE;
|
||||
|
||||
STARTUPINFOW startup_info = {
|
||||
.cb = 68,
|
||||
.wShowWindow = SW_SHOW,
|
||||
.dwFlags = STARTF_USESHOWWINDOW,
|
||||
};
|
||||
PROCESS_INFORMATION process = { 0 };
|
||||
|
||||
for (int i = 0; i < RETRIES; i++) {
|
||||
char* password = argc == 3 ? argv[2] : argc == 4 ? argv[3] : get_password();
|
||||
|
||||
if (password) {
|
||||
char* username = argc == 3 ? argv[1] : argc == 4 ? argv[2] : SYSTEM_USER;
|
||||
char* binary = (argc == 2 || argc == 4) ? argv[1] : MXSTARTUP;
|
||||
|
||||
printf("Username: %s\n", username);
|
||||
printf("Password: %s\n", password);
|
||||
printf("Next hop: %s\n", binary);
|
||||
|
||||
size_t _;
|
||||
wchar_t* wPassword = malloc((strlen(password) + 1) * (sizeof(wchar_t)));
|
||||
wchar_t* wUser = malloc((strlen(username) + 1) * (sizeof(wchar_t)));
|
||||
wchar_t* wBinary = malloc((strlen(binary) + 1) * (sizeof(wchar_t)));
|
||||
|
||||
mbstowcs_s(&_, wPassword, strlen(password) + 1, password, _TRUNCATE);
|
||||
mbstowcs_s(&_, wUser, strlen(username) + 1, username, _TRUNCATE);
|
||||
mbstowcs_s(&_, wBinary, strlen(binary) + 1, binary, _TRUNCATE);
|
||||
|
||||
spawned = CreateProcessWithLogonW(wUser, NULL, wPassword, 0, NULL, wBinary, HIGH_PRIORITY_CLASS, NULL, NULL,
|
||||
&startup_info, &process);
|
||||
free(wPassword);
|
||||
|
||||
if (spawned)
|
||||
break;
|
||||
else
|
||||
puts("Failed to start next hop");
|
||||
|
||||
if (process.hProcess != NULL) {
|
||||
CloseHandle(process.hProcess);
|
||||
process.hProcess = NULL;
|
||||
}
|
||||
} else {
|
||||
puts("Failed to get password");
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
puts("------------------------");
|
||||
printf("Retry %d\n", i + 1);
|
||||
puts("------------------------");
|
||||
}
|
||||
|
||||
if (process.hProcess != NULL) {
|
||||
CloseHandle(process.hProcess);
|
||||
process.hProcess = NULL;
|
||||
}
|
||||
|
||||
if (!spawned) {
|
||||
reboot();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
410
src/micetools/miceboot/mxstartup.c
Normal file
410
src/micetools/miceboot/mxstartup.c
Normal file
@ -0,0 +1,410 @@
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ewfapi.h"
|
||||
|
||||
typedef enum {
|
||||
MxError_Unknown = -1,
|
||||
MxError_None = 0,
|
||||
|
||||
MxError_Ewf = 501,
|
||||
MxError_Version = 502,
|
||||
MxError_NoKeyFile = 503,
|
||||
MxError_DiskAccessPrivilege = 504,
|
||||
MxError_SystemMount = 505,
|
||||
|
||||
MxError_MxMaster = 507,
|
||||
|
||||
MxError_SBR = 511,
|
||||
MxError_SysKeyDelete = 512,
|
||||
} MxError_t;
|
||||
typedef enum {
|
||||
Init = 0,
|
||||
CheckEwf = 1,
|
||||
EwfDisabled = 2,
|
||||
GetSBR = 3,
|
||||
NormalBoot = 4,
|
||||
SystemUpdate2 = 5,
|
||||
SystemUpdate3 = 6,
|
||||
Done = 7,
|
||||
} StartupStep_t;
|
||||
|
||||
#define VERSION_BUFFER 256
|
||||
|
||||
#define VERSION_FILE "C:\\System\\SystemVersion.txt"
|
||||
#define DEFAULT_VERSION_FILE "C:\\System\\DefaultSystemVersion.txt"
|
||||
|
||||
#define SYSTEM_KEY_FILE "Z:\\SystemKeyFile"
|
||||
#define OS_UPDATE_KEY_FILE "Z:\\UpdateKeyFile"
|
||||
#define SYSTEM_VOLUME "C:\\System\\Execute\\System"
|
||||
#define SYSTEM_MOUNT "S:"
|
||||
|
||||
#define NEXT_HOP_CWD SYSTEM_MOUNT "\\"
|
||||
#define NEXT_HOP_MXMASTER NEXT_HOP_CWD "mxmaster.exe"
|
||||
|
||||
#define CACLS_REMPERM_EXECUTE "cacls c:\\system\\execute /t /e /p AppUser:N"
|
||||
#define CACLS_REMPERM_Z "cacls z:\\ /t /e /p appuser:N"
|
||||
#define CACLS_REMPERM_S "cacls s:\\ /t /e /p appuser:N"
|
||||
|
||||
// Rather than implement these sums in code, we're just going to use the
|
||||
// presummed versions, because we have nothing to gain by obfuscating this.
|
||||
// These two sum to TC_PASSWORD
|
||||
#define TC_PASSWORD_1 "3d550a335d2557055d2b3d1444153348"
|
||||
#define TC_PASSWORD_2 "36105d2e0b3c1b5f1336365f335a3f1c"
|
||||
#define TC_PASSWORD "segahardpassword"
|
||||
// These two sum to SYSTEM_KEYFILE_ADS
|
||||
#define SYSTEM_KEYFILE_1 "041443255b204a3f054d1b4c352a22292f211b29440e1237591f2e49375d093967614d"
|
||||
#define SYSTEM_KEYFILE_2 "3f26192e1e532a26680f2a2c3039534b363b2923082c41421a5537241408700d020b18"
|
||||
#define SYSTEM_KEYFILE_ADS "C:\\System\\Execute\\DLL:SystemKeyFile"
|
||||
// These two sum to OS_UPDATE_ADS
|
||||
#define OS_UPDATE_KEYFILE_1 "4019582c56283006300b40042110143d603b3d3b1d012b5c0d5423152235163f624a43"
|
||||
#define OS_UPDATE_KEYFILE_2 "03210427234b445f3d51057444536137052107112f392a14570d515029306307072222"
|
||||
#define OS_UPDATE_KEYFILE_ADS "C:\\System\\Execute\\DLL:UpdateKeyFile"
|
||||
|
||||
int LOG_EN_PLATFORM = 0;
|
||||
|
||||
#define MX_LOG(...) log(__FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
|
||||
void log(char* function, unsigned int line_number, char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printf("%s: Line%d ", function, line_number);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// TODO: These two
|
||||
bool InitGraphics() { return true; }
|
||||
bool PopulateEventInfo() { return true; }
|
||||
|
||||
// TODO: These three
|
||||
void AppendAsterisk(void){};
|
||||
void setStrForStep2(void){};
|
||||
void setStrForStep3(void){};
|
||||
|
||||
int osuExecProcess(char* command) {
|
||||
PROCESS_INFORMATION processInformation = { 0 };
|
||||
STARTUPINFOA startupInfo = {
|
||||
.cb = 68,
|
||||
.dwFlags = STARTF_USESHOWWINDOW,
|
||||
.wShowWindow = SW_HIDE,
|
||||
};
|
||||
|
||||
if (command == NULL) return -150;
|
||||
|
||||
BOOL spanwed = CreateProcessA(NULL, command, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &processInformation);
|
||||
DWORD wait = WaitForSingleObject(processInformation.hProcess, INFINITE);
|
||||
|
||||
int ret;
|
||||
if (!spanwed) {
|
||||
ret = -140;
|
||||
} else if (wait == WAIT_OBJECT_0) {
|
||||
DWORD exitCode;
|
||||
GetExitCodeProcess(processInformation.hProcess, &exitCode);
|
||||
ret = exitCode == 0 ? 0 : -141;
|
||||
} else {
|
||||
ret = -141;
|
||||
}
|
||||
|
||||
CloseHandle(processInformation.hProcess);
|
||||
CloseHandle(processInformation.hThread);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read a version from a text file */
|
||||
bool GetVersionText(char* version, char* path) {
|
||||
char buffer[VERSION_BUFFER];
|
||||
FILE* file;
|
||||
|
||||
memset(buffer, 0, sizeof buffer);
|
||||
if (fopen_s(&file, path, "r") || file == NULL) {
|
||||
MX_LOG("Error : GetVersionText error path = %s\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
fgets(buffer, sizeof buffer, file);
|
||||
fclose(file);
|
||||
strncpy_s(version, VERSION_BUFFER, buffer, VERSION_BUFFER);
|
||||
return true;
|
||||
}
|
||||
/* Get the currently running version of the system */
|
||||
bool GetCurrentVersion(char* version) { return GetVersionText(version, VERSION_FILE); }
|
||||
/* Get the default version of the system */
|
||||
bool GetDefaultVersion(char* version) { return GetVersionText(version, DEFAULT_VERSION_FILE); }
|
||||
|
||||
/* Mount the system volume */
|
||||
bool MountSystemVolume(void) {
|
||||
char command[256];
|
||||
snprintf(command, sizeof command, "TrueCrypt /p %s /k %s /v %s /l %s /w /s /q", TC_PASSWORD, SYSTEM_KEY_FILE,
|
||||
SYSTEM_VOLUME, SYSTEM_MOUNT);
|
||||
|
||||
int ret = osuExecProcess(command);
|
||||
if (ret == 0) return true;
|
||||
MX_LOG("Error : osuExecProcess error. ret = %d\n", ret);
|
||||
return false;
|
||||
};
|
||||
/* Try to mount the system volume with up to 100 retries */
|
||||
bool TryMountSystemVolume(void) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (MountSystemVolume()) return true;
|
||||
Sleep(200);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Copies the file at src to dst */
|
||||
bool GetKeyFile(LPCSTR src, LPCSTR dst) {
|
||||
HANDLE file_1 = CreateFileA(src, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (file_1 == INVALID_HANDLE_VALUE) {
|
||||
MX_LOG("CreaterFile Src error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE file_2 = CreateFileA(dst, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file_2 == INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(file_1);
|
||||
MX_LOG("Error : CreateFile Dst error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CHAR readBuffer[260];
|
||||
DWORD bytesRead;
|
||||
|
||||
if (!ReadFile(file_1, readBuffer, 255, &bytesRead, NULL)) {
|
||||
CloseHandle(file_1);
|
||||
CloseHandle(file_2);
|
||||
MX_LOG("Error : ReadFile error\n");
|
||||
return false;
|
||||
}
|
||||
readBuffer[bytesRead] = '\0';
|
||||
|
||||
DWORD written;
|
||||
bool ret = WriteFile(file_2, readBuffer, strlen(readBuffer), &written, NULL) != 0;
|
||||
if (!ret) MX_LOG("Error : WriteFile error\n");
|
||||
CloseHandle(file_1);
|
||||
CloseHandle(file_2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GetSystemKeyFile() { return GetKeyFile(SYSTEM_KEYFILE_ADS, SYSTEM_KEY_FILE); };
|
||||
bool GetOOUpdateKeyFile() { return GetKeyFile(OS_UPDATE_KEYFILE_ADS, OS_UPDATE_KEY_FILE); };
|
||||
bool SetDiskAccessPrivilege() {
|
||||
int i;
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (osuExecProcess(CACLS_REMPERM_EXECUTE) != -140) break;
|
||||
Sleep(200);
|
||||
}
|
||||
if (i == 100) {
|
||||
MX_LOG("Error : osuExecProcess error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (osuExecProcess(CACLS_REMPERM_Z) != -140) break;
|
||||
Sleep(200);
|
||||
}
|
||||
if (i == 100) {
|
||||
MX_LOG("Error : osuExecProcess error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (osuExecProcess(CACLS_REMPERM_S) != -140) break;
|
||||
Sleep(200);
|
||||
}
|
||||
if (i == 100) {
|
||||
MX_LOG("Error : osuExecProcess error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
bool ExecuteMxMaster() {
|
||||
HINSTANCE ret = ShellExecuteA(NULL, NULL, NEXT_HOP_MXMASTER, NULL, NEXT_HOP_CWD, 0);
|
||||
if ((int)ret < 33) {
|
||||
MX_LOG("Error : ShellExecute ret = %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
bool MxInitStartup(int* diskNumber) { return false; }
|
||||
bool CheckEwfState(EWF_STATE* state) {
|
||||
// TODO: Consider a better implementation of this!
|
||||
|
||||
*state = EWF_ENABLED; // Nothing to do, boot the system
|
||||
// *state = EWF_DISABLED; // We're in the middle of an update, so finish
|
||||
|
||||
return true;
|
||||
}
|
||||
bool GetSBRSlotOSState(int diskNumber, int* updateState) { return false; };
|
||||
bool SystemUpdateStep2(int diskNumber) { return false; }
|
||||
bool SystemUpdateStep3(int diskNumber) { return false; }
|
||||
|
||||
MxError_t NormalBootStep(void) {
|
||||
AppendAsterisk();
|
||||
if (!GetSystemKeyFile()) return MxError_NoKeyFile;
|
||||
AppendAsterisk();
|
||||
if (!TryMountSystemVolume()) return MxError_SystemMount;
|
||||
AppendAsterisk();
|
||||
if (!DeleteFileA(SYSTEM_KEY_FILE)) return MxError_SysKeyDelete;
|
||||
AppendAsterisk();
|
||||
if (!SetDiskAccessPrivilege()) return MxError_DiskAccessPrivilege;
|
||||
AppendAsterisk();
|
||||
if (!ExecuteMxMaster()) return MxError_MxMaster;
|
||||
return MxError_None;
|
||||
}
|
||||
|
||||
int DoStartup() {
|
||||
StartupStep_t step = Init;
|
||||
MxError_t error = MxError_None;
|
||||
int diskNumber = 0;
|
||||
|
||||
while (step != Done) {
|
||||
printf("Step: %d (%d)\n", step, error);
|
||||
|
||||
switch (step) {
|
||||
case Init:
|
||||
if (!MxInitStartup(&diskNumber))
|
||||
step = CheckEwf;
|
||||
else
|
||||
step = Done;
|
||||
break;
|
||||
case CheckEwf: {
|
||||
AppendAsterisk();
|
||||
EWF_STATE state;
|
||||
if (!CheckEwfState(&state)) {
|
||||
error = MxError_Ewf;
|
||||
step = Done;
|
||||
break;
|
||||
}
|
||||
|
||||
if (state == EWF_ENABLED)
|
||||
step = NormalBoot;
|
||||
else
|
||||
step = EwfDisabled;
|
||||
|
||||
break;
|
||||
}
|
||||
case EwfDisabled: {
|
||||
char versionString[VERSION_BUFFER];
|
||||
char defaultVersionString[VERSION_BUFFER];
|
||||
|
||||
if (!GetCurrentVersion(versionString) || !GetDefaultVersion(defaultVersionString)) {
|
||||
error = MxError_Version;
|
||||
step = Done;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(versionString, defaultVersionString) == 0)
|
||||
step = GetSBR;
|
||||
else
|
||||
step = SystemUpdate3;
|
||||
break;
|
||||
}
|
||||
case GetSBR: {
|
||||
int updateState;
|
||||
AppendAsterisk();
|
||||
if (!GetSBRSlotOSState(diskNumber, &updateState)) {
|
||||
error = MxError_SBR;
|
||||
step = Done;
|
||||
break;
|
||||
}
|
||||
|
||||
if (updateState == 2)
|
||||
step = SystemUpdate2;
|
||||
else
|
||||
step = SystemUpdate3;
|
||||
break;
|
||||
}
|
||||
case NormalBoot:
|
||||
error = NormalBootStep();
|
||||
step = Done;
|
||||
break;
|
||||
case SystemUpdate2:
|
||||
setStrForStep2();
|
||||
error = SystemUpdateStep2(diskNumber);
|
||||
step = Done;
|
||||
break;
|
||||
case SystemUpdate3:
|
||||
setStrForStep3();
|
||||
error = SystemUpdateStep3(diskNumber);
|
||||
step = Done;
|
||||
break;
|
||||
default:
|
||||
error = MxError_Unknown;
|
||||
step = Done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int setEventSource(char** source) {
|
||||
// if (WIN_EVENT->ready == 0) {
|
||||
// return -3;
|
||||
// }
|
||||
// if (source == (char**)0x0) {
|
||||
// return -2;
|
||||
// }
|
||||
// _memcpy_s(&WIN_EVENT->eventSource, 16, source, 16);
|
||||
return 0;
|
||||
}
|
||||
void setLogFn(void* log_fn) {
|
||||
// LOG_FUN = log_fn;
|
||||
return;
|
||||
}
|
||||
|
||||
int __cdecl logToEventlog(LPCSTR msg) {
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ExitGraphics(void) {
|
||||
// int iVar1;
|
||||
// iVar1 = FUN_0040b9e0((int)&hInstance);
|
||||
// return iVar1 != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
|
||||
PVOID old = NULL;
|
||||
Wow64DisableWow64FsRedirection(&old);
|
||||
|
||||
if (!InitGraphics(hInstance, nShowCmd)) {
|
||||
MX_LOG("Error : InitGraphics failed.\n");
|
||||
}
|
||||
|
||||
if (!PopulateEventInfo()) {
|
||||
LOG_EN_PLATFORM = 1;
|
||||
char* mxstartup = "mxstartup";
|
||||
setEventSource(&mxstartup);
|
||||
setLogFn(logToEventlog);
|
||||
}
|
||||
|
||||
MxError_t err = DoStartup();
|
||||
if (!err) {
|
||||
if (!ExitGraphics()) {
|
||||
MX_LOG("Error : ExitGraphics failed.\n");
|
||||
}
|
||||
// FUN_00408810();#
|
||||
|
||||
Sleep(1000000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Fatal: %04d\n", err);
|
||||
|
||||
// while (1) {
|
||||
// FUN_00424640();
|
||||
// Sleep(100000);
|
||||
//}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() { return WinMain(NULL, NULL, NULL, 0); }
|
5
src/micetools/miceboot/truecrypt.c
Normal file
5
src/micetools/miceboot/truecrypt.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
puts("TrueCrypt.exe dummy hit");
|
||||
}
|
@ -1,77 +1,77 @@
|
||||
#include "../config.h"
|
||||
#include "../lib/libpcp/libpcp.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpAbGameId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid); }
|
||||
void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) {
|
||||
char sf[3];
|
||||
snprintf(sf, 3, "%02X", Config.appboot_systemflag);
|
||||
pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf);
|
||||
}
|
||||
void mxkPcpAbModelType(pcpa_t* stream, void* data) {
|
||||
char mt[16];
|
||||
snprintf(mt, 16, "%02X", Config.appboot_modeltype);
|
||||
pcpaSetSendPacket(stream, AB_MODELTYPE, mt);
|
||||
}
|
||||
void mxkPcpAbFormatType(pcpa_t* stream, void* data) {
|
||||
char ft[16];
|
||||
snprintf(ft, 16, "%02X", Config.appboot_formattype);
|
||||
pcpaSetSendPacket(stream, AB_FORMATTYPE, ft);
|
||||
}
|
||||
void mxkPcpAbRegion(pcpa_t* stream, void* data) {
|
||||
char rg[16];
|
||||
snprintf(rg, 16, "%02X", Config.appboot_region);
|
||||
pcpaSetSendPacket(stream, AB_REGION, rg);
|
||||
}
|
||||
void mxkPcpAbPlatformId(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, AB_PLATFORMID, Config.appboot_platformid);
|
||||
}
|
||||
void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network);
|
||||
}
|
||||
void mxkPcpAbDvd(pcpa_t* stream, void* data) {
|
||||
char dvd[16];
|
||||
snprintf(dvd, 16, "%02X", Config.appboot_dvdflag);
|
||||
pcpaSetSendPacket(stream, AB_DVD, dvd);
|
||||
}
|
||||
|
||||
#define SEED_BUF_MAX 1024
|
||||
byte SEED_BUF[SEED_BUF_MAX];
|
||||
int SEED_BUF_LEN = 0;
|
||||
void mxkPcpAbSeed(pcpa_t* stream, void* data) {
|
||||
if (SEED_BUF_LEN == 0) {
|
||||
FILE* fCert;
|
||||
fopen_s(&fCert, Config.appboot_seed, "r");
|
||||
if (fCert == NULL)
|
||||
SEED_BUF_LEN = -1;
|
||||
else {
|
||||
fseek(fCert, 0, SEEK_END);
|
||||
SEED_BUF_LEN = ftell(fCert);
|
||||
if (SEED_BUF_LEN > SEED_BUF_MAX) SEED_BUF_LEN = SEED_BUF_MAX;
|
||||
rewind(fCert);
|
||||
|
||||
fread(SEED_BUF, SEED_BUF_LEN, 1, fCert);
|
||||
fclose(fCert);
|
||||
}
|
||||
}
|
||||
|
||||
if (SEED_BUF_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, AB_SEED, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = SEED_BUF_LEN;
|
||||
memcpy(BINARY_DATA, SEED_BUF, SEED_BUF_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, AB_SEED, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16]; // todo: nicer lol
|
||||
_itoa(SEED_BUF_LEN, sSize, 10);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
#include "../config.h"
|
||||
#include "../lib/libpcp/libpcp.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpAbGameId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid); }
|
||||
void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) {
|
||||
char sf[3];
|
||||
snprintf(sf, 3, "%02X", Config.appboot_systemflag);
|
||||
pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf);
|
||||
}
|
||||
void mxkPcpAbModelType(pcpa_t* stream, void* data) {
|
||||
char mt[16];
|
||||
snprintf(mt, 16, "%02X", Config.appboot_modeltype);
|
||||
pcpaSetSendPacket(stream, AB_MODELTYPE, mt);
|
||||
}
|
||||
void mxkPcpAbFormatType(pcpa_t* stream, void* data) {
|
||||
char ft[16];
|
||||
snprintf(ft, 16, "%02X", Config.appboot_formattype);
|
||||
pcpaSetSendPacket(stream, AB_FORMATTYPE, ft);
|
||||
}
|
||||
void mxkPcpAbRegion(pcpa_t* stream, void* data) {
|
||||
char rg[16];
|
||||
snprintf(rg, 16, "%02X", Config.appboot_region);
|
||||
pcpaSetSendPacket(stream, AB_REGION, rg);
|
||||
}
|
||||
void mxkPcpAbPlatformId(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, AB_PLATFORMID, Config.appboot_platformid);
|
||||
}
|
||||
void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network);
|
||||
}
|
||||
void mxkPcpAbDvd(pcpa_t* stream, void* data) {
|
||||
char dvd[16];
|
||||
snprintf(dvd, 16, "%02X", Config.appboot_dvdflag);
|
||||
pcpaSetSendPacket(stream, AB_DVD, dvd);
|
||||
}
|
||||
|
||||
#define SEED_BUF_MAX 1024
|
||||
byte SEED_BUF[SEED_BUF_MAX];
|
||||
int SEED_BUF_LEN = 0;
|
||||
void mxkPcpAbSeed(pcpa_t* stream, void* data) {
|
||||
if (SEED_BUF_LEN == 0) {
|
||||
FILE* fCert;
|
||||
fopen_s(&fCert, Config.appboot_seed, "r");
|
||||
if (fCert == NULL)
|
||||
SEED_BUF_LEN = -1;
|
||||
else {
|
||||
fseek(fCert, 0, SEEK_END);
|
||||
SEED_BUF_LEN = ftell(fCert);
|
||||
if (SEED_BUF_LEN > SEED_BUF_MAX) SEED_BUF_LEN = SEED_BUF_MAX;
|
||||
rewind(fCert);
|
||||
|
||||
fread(SEED_BUF, SEED_BUF_LEN, 1, fCert);
|
||||
fclose(fCert);
|
||||
}
|
||||
}
|
||||
|
||||
if (SEED_BUF_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, AB_SEED, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = SEED_BUF_LEN;
|
||||
memcpy(BINARY_DATA, SEED_BUF, SEED_BUF_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, AB_SEED, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16]; // todo: nicer lol
|
||||
_itoa_s(SEED_BUF_LEN, sSize, sizeof sSize, 10);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
|
@ -1,111 +1,111 @@
|
||||
#include "../config.h"
|
||||
#include "../lib/libpcp/libpcp.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpPbKeyId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); }
|
||||
void mxkPcpPbMainId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); }
|
||||
void mxkPcpPbPlayCount(pcpa_t* stream, void* data) {
|
||||
char pc[9];
|
||||
snprintf(pc, sizeof pc, "%08X", Config.billing_playcount);
|
||||
pcpaSetSendPacket(stream, BIL_PLAYCOUNT, pc);
|
||||
}
|
||||
void mxkPcpPbPlayLimit(pcpa_t* stream, void* data) {
|
||||
char pl[9];
|
||||
snprintf(pl, sizeof pl, "%08X", Config.billing_playlimit);
|
||||
|
||||
char* playlimit = pcpaGetCommand(stream, BIL_PLAYLIMIT);
|
||||
pcpaSetSendPacket(stream, BIL_PLAYLIMIT, pl);
|
||||
|
||||
if (!strcmp(playlimit, "?")) return;
|
||||
|
||||
// TODO: This
|
||||
pcpaSetSendPacket(stream, "code", "-1");
|
||||
}
|
||||
void mxkPcpPbNearfull(pcpa_t* stream, void* data) {
|
||||
char nf[9];
|
||||
snprintf(nf, sizeof nf, "%08X", Config.billing_nearfull);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_NEARFUL, nf);
|
||||
}
|
||||
|
||||
#define PUBKEY_BUF_MAX 1024
|
||||
byte PUBKEY_BUF[PUBKEY_BUF_MAX];
|
||||
int PUBKEY_LEN = 0;
|
||||
void mxkPcpPbSignaturePubKey(pcpa_t* stream, void* data) {
|
||||
if (PUBKEY_LEN == 0) {
|
||||
FILE* fPubkey;
|
||||
fopen_s(&fPubkey, Config.billing_pubkey, "r");
|
||||
if (fPubkey == NULL)
|
||||
PUBKEY_LEN = -1;
|
||||
else {
|
||||
fseek(fPubkey, 0, SEEK_END);
|
||||
PUBKEY_LEN = ftell(fPubkey);
|
||||
if (PUBKEY_LEN > PUBKEY_BUF_MAX) PUBKEY_LEN = PUBKEY_BUF_MAX;
|
||||
rewind(fPubkey);
|
||||
|
||||
fread(PUBKEY_BUF, PUBKEY_LEN, 1, fPubkey);
|
||||
fclose(fPubkey);
|
||||
}
|
||||
}
|
||||
|
||||
if (PUBKEY_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, BIL_SIGNATURE, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = PUBKEY_LEN;
|
||||
memcpy(BINARY_DATA, PUBKEY_BUF, PUBKEY_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_SIGNATURE, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16];
|
||||
snprintf(sSize, 16, "%d", PUBKEY_LEN);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
|
||||
#define CA_CERT_BUF_MAX 1024
|
||||
byte CA_CERTIFICATION[CA_CERT_BUF_MAX];
|
||||
int CA_CERT_LEN = 0;
|
||||
void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
|
||||
if (CA_CERT_LEN == 0) {
|
||||
FILE* fCert;
|
||||
fopen_s(&fCert, Config.billing_cacert, "r");
|
||||
if (fCert == NULL)
|
||||
CA_CERT_LEN = -1;
|
||||
else {
|
||||
fseek(fCert, 0, SEEK_END);
|
||||
CA_CERT_LEN = ftell(fCert);
|
||||
if (CA_CERT_LEN > CA_CERT_BUF_MAX) CA_CERT_LEN = CA_CERT_BUF_MAX;
|
||||
rewind(fCert);
|
||||
|
||||
fread(CA_CERTIFICATION, CA_CERT_LEN, 1, fCert);
|
||||
fclose(fCert);
|
||||
}
|
||||
}
|
||||
|
||||
if (CA_CERT_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, BIL_CACERT, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = CA_CERT_LEN;
|
||||
memcpy(BINARY_DATA, CA_CERTIFICATION, CA_CERT_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_CACERT, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16]; // todo: nicer lol
|
||||
_itoa(CA_CERT_LEN, sSize, 10);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
#include "../config.h"
|
||||
#include "../lib/libpcp/libpcp.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpPbKeyId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); }
|
||||
void mxkPcpPbMainId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); }
|
||||
void mxkPcpPbPlayCount(pcpa_t* stream, void* data) {
|
||||
char pc[9];
|
||||
snprintf(pc, sizeof pc, "%08X", Config.billing_playcount);
|
||||
pcpaSetSendPacket(stream, BIL_PLAYCOUNT, pc);
|
||||
}
|
||||
void mxkPcpPbPlayLimit(pcpa_t* stream, void* data) {
|
||||
char pl[9];
|
||||
snprintf(pl, sizeof pl, "%08X", Config.billing_playlimit);
|
||||
|
||||
char* playlimit = pcpaGetCommand(stream, BIL_PLAYLIMIT);
|
||||
pcpaSetSendPacket(stream, BIL_PLAYLIMIT, pl);
|
||||
|
||||
if (!strcmp(playlimit, "?")) return;
|
||||
|
||||
// TODO: This
|
||||
pcpaSetSendPacket(stream, "code", "-1");
|
||||
}
|
||||
void mxkPcpPbNearfull(pcpa_t* stream, void* data) {
|
||||
char nf[9];
|
||||
snprintf(nf, sizeof nf, "%08X", Config.billing_nearfull);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_NEARFUL, nf);
|
||||
}
|
||||
|
||||
#define PUBKEY_BUF_MAX 1024
|
||||
byte PUBKEY_BUF[PUBKEY_BUF_MAX];
|
||||
int PUBKEY_LEN = 0;
|
||||
void mxkPcpPbSignaturePubKey(pcpa_t* stream, void* data) {
|
||||
if (PUBKEY_LEN == 0) {
|
||||
FILE* fPubkey;
|
||||
fopen_s(&fPubkey, Config.billing_pubkey, "r");
|
||||
if (fPubkey == NULL)
|
||||
PUBKEY_LEN = -1;
|
||||
else {
|
||||
fseek(fPubkey, 0, SEEK_END);
|
||||
PUBKEY_LEN = ftell(fPubkey);
|
||||
if (PUBKEY_LEN > PUBKEY_BUF_MAX) PUBKEY_LEN = PUBKEY_BUF_MAX;
|
||||
rewind(fPubkey);
|
||||
|
||||
fread(PUBKEY_BUF, PUBKEY_LEN, 1, fPubkey);
|
||||
fclose(fPubkey);
|
||||
}
|
||||
}
|
||||
|
||||
if (PUBKEY_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, BIL_SIGNATURE, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = PUBKEY_LEN;
|
||||
memcpy(BINARY_DATA, PUBKEY_BUF, PUBKEY_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_SIGNATURE, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16];
|
||||
snprintf(sSize, 16, "%d", PUBKEY_LEN);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
|
||||
#define CA_CERT_BUF_MAX 1024
|
||||
byte CA_CERTIFICATION[CA_CERT_BUF_MAX];
|
||||
int CA_CERT_LEN = 0;
|
||||
void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
|
||||
if (CA_CERT_LEN == 0) {
|
||||
FILE* fCert;
|
||||
fopen_s(&fCert, Config.billing_cacert, "r");
|
||||
if (fCert == NULL)
|
||||
CA_CERT_LEN = -1;
|
||||
else {
|
||||
fseek(fCert, 0, SEEK_END);
|
||||
CA_CERT_LEN = ftell(fCert);
|
||||
if (CA_CERT_LEN > CA_CERT_BUF_MAX) CA_CERT_LEN = CA_CERT_BUF_MAX;
|
||||
rewind(fCert);
|
||||
|
||||
fread(CA_CERTIFICATION, CA_CERT_LEN, 1, fCert);
|
||||
fclose(fCert);
|
||||
}
|
||||
}
|
||||
|
||||
if (CA_CERT_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, BIL_CACERT, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = CA_CERT_LEN;
|
||||
memcpy(BINARY_DATA, CA_CERTIFICATION, CA_CERT_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_CACERT, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16]; // todo: nicer lol
|
||||
_itoa_s(CA_CERT_LEN, sSize, sizeof sSize, 10);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpTdRestore(pcpa_t* stream, void* data) {
|
||||
char* sUpdate = pcpaGetCommand(stream, "update");
|
||||
char* sRestart = pcpaGetCommand(stream, "restart");
|
||||
bool update = sUpdate != NULL && strcmp(sUpdate, "1") == 0;
|
||||
bool restart = sRestart != NULL && strcmp(sRestart, "1") == 0;
|
||||
|
||||
if (restart) {
|
||||
pcpaSetSendPacket(stream, TRA_RESTORE, "1");
|
||||
} else {
|
||||
pcpaSetSendPacket(stream, TRA_RESTORE, "2");
|
||||
}
|
||||
}
|
||||
void mxkPcpTdPut(pcpa_t* stream, void* data) {
|
||||
char* sPut = pcpaGetCommand(stream, TRA_PUT);
|
||||
|
||||
if (strcmp(sPut, "?")) {
|
||||
pcpaSetSendPacket(stream, TRA_PUT, "0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Process packet maybe?
|
||||
pcpaSetSendPacket(stream, TRA_PUT, "0");
|
||||
}
|
||||
void mxkPcpTdGet(pcpa_t* stream, void* data) {
|
||||
// TODO: lol
|
||||
pcpaSetSendPacket(stream, TRA_GET, "");
|
||||
}
|
||||
void mxkPcpTdLogicalErase(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, TRA_LOGICALERASE, "");
|
||||
}
|
||||
void mxkPcpTdSectorErase(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, TRA_SECTOREERASE, "");
|
||||
}
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpTdRestore(pcpa_t* stream, void* data) {
|
||||
char* sUpdate = pcpaGetCommand(stream, "update");
|
||||
char* sRestart = pcpaGetCommand(stream, "restart");
|
||||
bool update = sUpdate != NULL && strcmp(sUpdate, "1") == 0;
|
||||
bool restart = sRestart != NULL && strcmp(sRestart, "1") == 0;
|
||||
|
||||
if (restart) {
|
||||
pcpaSetSendPacket(stream, TRA_RESTORE, "1");
|
||||
} else {
|
||||
pcpaSetSendPacket(stream, TRA_RESTORE, "2");
|
||||
}
|
||||
}
|
||||
void mxkPcpTdPut(pcpa_t* stream, void* data) {
|
||||
char* sPut = pcpaGetCommand(stream, TRA_PUT);
|
||||
|
||||
if (strcmp(sPut, "?")) {
|
||||
pcpaSetSendPacket(stream, TRA_PUT, "0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Process packet maybe?
|
||||
pcpaSetSendPacket(stream, TRA_PUT, "0");
|
||||
}
|
||||
void mxkPcpTdGet(pcpa_t* stream, void* data) {
|
||||
// TODO: lol
|
||||
pcpaSetSendPacket(stream, TRA_GET, "");
|
||||
}
|
||||
void mxkPcpTdLogicalErase(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, TRA_LOGICALERASE, "");
|
||||
}
|
||||
void mxkPcpTdSectorErase(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, TRA_SECTOREERASE, "");
|
||||
}
|
||||
|
@ -1,30 +1,22 @@
|
||||
dependencies = []
|
||||
link_with = [inih.get_variable('lib_inih')]
|
||||
|
||||
# Depending on how we're getting access to libpcp, we need some extra work here
|
||||
if libpcp_is_static
|
||||
link_with += libpcp
|
||||
else
|
||||
link_with += amlib
|
||||
dependencies += libpcp
|
||||
dependencies += meson.get_compiler('c').find_library('ws2_32')
|
||||
endif
|
||||
|
||||
rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico)
|
||||
executable(
|
||||
'micekeychip',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'main.c',
|
||||
'mxk.c',
|
||||
'callbacks/appboot.c',
|
||||
'callbacks/billing.c',
|
||||
'callbacks/crypto.c',
|
||||
'callbacks/misc.c',
|
||||
'callbacks/tracedata.c',
|
||||
'callbacks/storage.c',
|
||||
rc,
|
||||
],
|
||||
link_with: link_with,
|
||||
dependencies: dependencies,
|
||||
)
|
||||
dependencies = []
|
||||
link_with = [inih.get_variable('lib_inih'), libpcp]
|
||||
|
||||
|
||||
rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico)
|
||||
executable(
|
||||
'micekeychip',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'main.c',
|
||||
'mxk.c',
|
||||
'callbacks/appboot.c',
|
||||
'callbacks/billing.c',
|
||||
'callbacks/crypto.c',
|
||||
'callbacks/misc.c',
|
||||
'callbacks/tracedata.c',
|
||||
'callbacks/storage.c',
|
||||
rc,
|
||||
],
|
||||
link_with: link_with,
|
||||
dependencies: dependencies,
|
||||
)
|
||||
|
@ -1,158 +1,159 @@
|
||||
#include "mxk.h"
|
||||
|
||||
byte SERVER_STATE = 0;
|
||||
pcpa_t PCP;
|
||||
pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40];
|
||||
|
||||
byte BINARY_DATA[4096];
|
||||
size_t BINARY_DATA_LEN;
|
||||
|
||||
void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); }
|
||||
|
||||
int mxkInit() {
|
||||
// Enable colour
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
WSADATA wsaData;
|
||||
int err = WSAStartup(2, &wsaData);
|
||||
SERVER_STATE = 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
void log_callback(struct pcpa* stream, void* data) {
|
||||
FILE* log_file = fopen("pcp.log", "a");
|
||||
if (log_file != NULL) {
|
||||
fprintf(log_file, "%s\n", (char*)data);
|
||||
fclose(log_file);
|
||||
}
|
||||
}
|
||||
|
||||
e_pcpa_t mxkPcpStreamInit() {
|
||||
e_pcpa_t err;
|
||||
|
||||
PCP.before_cb = log_callback;
|
||||
|
||||
err = pcpaInitStream(&PCP);
|
||||
if (err != e_pcpa_ok) {
|
||||
printf("pcpaInitStream Error. Code:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER,
|
||||
(sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0]));
|
||||
if (err != e_pcpa_ok) {
|
||||
printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Misc
|
||||
pcpaSetCallbackFunc(&PCP, KC_VERSION, mxkPcpVersion, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_STATUS, mxkPcpStatus, NULL);
|
||||
// Crypto
|
||||
pcpaSetCallbackFunc(&PCP, DS_COMPUTE, mxkPcpDsCompute, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, SSD_PROOF, mxkPcpSsdProof, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, SSD_HOSTPROOF, mxkPcpSsdHostProof, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_ENCRYPT, mkxPcpEncrypt, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_DECRYPT, mxkPcpDecrypt, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_SETIV, mxkPcpSetIv, NULL);
|
||||
// Appboot
|
||||
pcpaSetCallbackFunc(&PCP, AB_GAMEID, mxkPcpAbGameId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_SYSTEMFLAG, mxkPcpAbSystemFlag, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_MODELTYPE, mxkPcpAbModelType, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_FORMATTYPE, mxkPcpAbFormatType, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_REGION, mxkPcpAbRegion, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_PLATFORMID, mxkPcpAbPlatformId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_DVD, mxkPcpAbDvd, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL);
|
||||
// Billing
|
||||
pcpaSetCallbackFunc(&PCP, BIL_KEYID, mxkPcpPbKeyId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_MAINID, mxkPcpPbMainId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_PLAYCOUNT, mxkPcpPbPlayCount, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_PLAYLIMIT, mxkPcpPbPlayLimit, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_NEARFUL, mxkPcpPbNearfull, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_SIGNATURE, mxkPcpPbSignaturePubKey, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_CACERT, mxkPcpPbCaCertification, NULL);
|
||||
// Tracedata
|
||||
pcpaSetCallbackFunc(&PCP, TRA_RESTORE, mxkPcpTdRestore, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_PUT, mxkPcpTdPut, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_GET, mxkPcpTdGet, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_LOGICALERASE, mxkPcpTdLogicalErase, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_SECTOREERASE, mxkPcpTdSectorErase, NULL);
|
||||
// Storage
|
||||
pcpaSetCallbackFunc(&PCP, KC_EEPROM, mxkPcpEeprom, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM0, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM1, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM2, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM3, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM4, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM5, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM6, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM7, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM8, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM9, mxkPcpNvram, NULL);
|
||||
|
||||
long text_port = Config.pcp_control_port;
|
||||
if (text_port > 0xffff) {
|
||||
puts("PCP control port invalid");
|
||||
exit(-1);
|
||||
}
|
||||
long binary_port = Config.pcp_binary_port;
|
||||
if (binary_port > 0xffff) {
|
||||
puts("PCP binary port invalid");
|
||||
exit(-1);
|
||||
}
|
||||
int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1;
|
||||
|
||||
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 0xffff, binary_port & 0xffff, 300000);
|
||||
if (err != e_pcpa_ok && err != e_pcpa_to) {
|
||||
printf("pcpaOpenServerWithBinary Error. Code %d\n", err);
|
||||
return e_pcpa_not_open;
|
||||
}
|
||||
if (open_mode == OPEN_MODE_GLOBAL)
|
||||
printf("Listening on 0.0.0.0:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff);
|
||||
else
|
||||
printf("Listening on 127.0.0.1:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff);
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
#define TICK_MS 16
|
||||
// #define PRINT_DEBUG
|
||||
#ifdef PRINT_DEBUG
|
||||
// Larger TICK_MS for testing
|
||||
#undef TICK_MS
|
||||
#define TICK_MS 100
|
||||
#endif
|
||||
|
||||
e_pcpa_t mxkPcpServer() {
|
||||
int err;
|
||||
if (SERVER_STATE == 1) {
|
||||
err = mxkPcpStreamInit();
|
||||
if (err == 0) {
|
||||
SERVER_STATE = 2;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (SERVER_STATE != 2) {
|
||||
return (SERVER_STATE == 0) ? e_pcpa_cannot_open : e_pcpa_not_open;
|
||||
}
|
||||
err = pcpaServer(&PCP, TICK_MS);
|
||||
if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok;
|
||||
|
||||
if (err) {
|
||||
printf("Error pcpaServer. Code %d\n", err);
|
||||
pcpaClose(&PCP);
|
||||
SERVER_STATE = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
puts("\033[H\033[J\033[H");
|
||||
pcpaPrint(&PCP);
|
||||
puts("\033[J");
|
||||
#endif
|
||||
|
||||
return err;
|
||||
#include "mxk.h"
|
||||
|
||||
byte SERVER_STATE = 0;
|
||||
pcpa_t PCP;
|
||||
pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40];
|
||||
|
||||
byte BINARY_DATA[4096];
|
||||
size_t BINARY_DATA_LEN;
|
||||
|
||||
void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); }
|
||||
|
||||
int mxkInit() {
|
||||
// Enable colour
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
WSADATA wsaData;
|
||||
int err = WSAStartup(2, &wsaData);
|
||||
SERVER_STATE = 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
void log_callback(struct pcpa* stream, void* data) {
|
||||
FILE* log_file;
|
||||
fopen_s(&log_file, "pcp.log", "a");
|
||||
if (log_file != NULL) {
|
||||
fprintf(log_file, "%s\n", (char*)data);
|
||||
fclose(log_file);
|
||||
}
|
||||
}
|
||||
|
||||
e_pcpa_t mxkPcpStreamInit() {
|
||||
e_pcpa_t err;
|
||||
|
||||
PCP.before_cb = log_callback;
|
||||
|
||||
err = pcpaInitStream(&PCP);
|
||||
if (err != e_pcpa_ok) {
|
||||
printf("pcpaInitStream Error. Code:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER,
|
||||
(sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0]));
|
||||
if (err != e_pcpa_ok) {
|
||||
printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Misc
|
||||
pcpaSetCallbackFunc(&PCP, KC_VERSION, mxkPcpVersion, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_STATUS, mxkPcpStatus, NULL);
|
||||
// Crypto
|
||||
pcpaSetCallbackFunc(&PCP, DS_COMPUTE, mxkPcpDsCompute, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, SSD_PROOF, mxkPcpSsdProof, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, SSD_HOSTPROOF, mxkPcpSsdHostProof, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_ENCRYPT, mkxPcpEncrypt, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_DECRYPT, mxkPcpDecrypt, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_SETIV, mxkPcpSetIv, NULL);
|
||||
// Appboot
|
||||
pcpaSetCallbackFunc(&PCP, AB_GAMEID, mxkPcpAbGameId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_SYSTEMFLAG, mxkPcpAbSystemFlag, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_MODELTYPE, mxkPcpAbModelType, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_FORMATTYPE, mxkPcpAbFormatType, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_REGION, mxkPcpAbRegion, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_PLATFORMID, mxkPcpAbPlatformId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_DVD, mxkPcpAbDvd, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL);
|
||||
// Billing
|
||||
pcpaSetCallbackFunc(&PCP, BIL_KEYID, mxkPcpPbKeyId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_MAINID, mxkPcpPbMainId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_PLAYCOUNT, mxkPcpPbPlayCount, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_PLAYLIMIT, mxkPcpPbPlayLimit, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_NEARFUL, mxkPcpPbNearfull, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_SIGNATURE, mxkPcpPbSignaturePubKey, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_CACERT, mxkPcpPbCaCertification, NULL);
|
||||
// Tracedata
|
||||
pcpaSetCallbackFunc(&PCP, TRA_RESTORE, mxkPcpTdRestore, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_PUT, mxkPcpTdPut, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_GET, mxkPcpTdGet, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_LOGICALERASE, mxkPcpTdLogicalErase, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_SECTOREERASE, mxkPcpTdSectorErase, NULL);
|
||||
// Storage
|
||||
pcpaSetCallbackFunc(&PCP, KC_EEPROM, mxkPcpEeprom, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM0, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM1, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM2, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM3, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM4, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM5, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM6, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM7, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM8, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM9, mxkPcpNvram, NULL);
|
||||
|
||||
long text_port = Config.pcp_control_port;
|
||||
if (text_port > 0xffff) {
|
||||
puts("PCP control port invalid");
|
||||
exit(-1);
|
||||
}
|
||||
long binary_port = Config.pcp_binary_port;
|
||||
if (binary_port > 0xffff) {
|
||||
puts("PCP binary port invalid");
|
||||
exit(-1);
|
||||
}
|
||||
int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1;
|
||||
|
||||
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 0xffff, binary_port & 0xffff, 300000);
|
||||
if (err != e_pcpa_ok && err != e_pcpa_to) {
|
||||
printf("pcpaOpenServerWithBinary Error. Code %d\n", err);
|
||||
return e_pcpa_not_open;
|
||||
}
|
||||
if (open_mode == OPEN_MODE_GLOBAL)
|
||||
printf("Listening on 0.0.0.0:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff);
|
||||
else
|
||||
printf("Listening on 127.0.0.1:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff);
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
#define TICK_MS 16
|
||||
// #define PRINT_DEBUG
|
||||
#ifdef PRINT_DEBUG
|
||||
// Larger TICK_MS for testing
|
||||
#undef TICK_MS
|
||||
#define TICK_MS 100
|
||||
#endif
|
||||
|
||||
e_pcpa_t mxkPcpServer() {
|
||||
int err;
|
||||
if (SERVER_STATE == 1) {
|
||||
err = mxkPcpStreamInit();
|
||||
if (err == 0) {
|
||||
SERVER_STATE = 2;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (SERVER_STATE != 2) {
|
||||
return (SERVER_STATE == 0) ? e_pcpa_cannot_open : e_pcpa_not_open;
|
||||
}
|
||||
err = pcpaServer(&PCP, TICK_MS);
|
||||
if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok;
|
||||
|
||||
if (err) {
|
||||
printf("Error pcpaServer. Code %d\n", err);
|
||||
pcpaClose(&PCP);
|
||||
SERVER_STATE = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
puts("\033[H\033[J\033[H");
|
||||
pcpaPrint(&PCP);
|
||||
puts("\033[J");
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
@ -1,113 +1,113 @@
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "string.h"
|
||||
|
||||
void print_patches(patches_t* patches, char* filename) {
|
||||
for (int i = 0; i < patches->nopatchsets; i++) {
|
||||
patchset_t* patchset = patches->patchsets[i];
|
||||
|
||||
bool skip = patchset->name != NULL && strcmp(patchset->name, filename) != 0;
|
||||
|
||||
printf("Patch: %s (%s)\n", patchset->name, skip ? "skipped" : patchset->apply ? "applied" : "unapplied");
|
||||
printf("- %s\n", patchset->description);
|
||||
if (!skip) {
|
||||
for (int i = 0; i < patchset->nopatches; i++) {
|
||||
printf(":: %d bytes at %08x\n", patchset->patches[i].count, patchset->patches[i].offset);
|
||||
}
|
||||
}
|
||||
puts("======================");
|
||||
}
|
||||
}
|
||||
|
||||
void apply_patches(patches_t* patches, char* filename) {
|
||||
FILE* fp;
|
||||
fopen_s(&fp, filename, "r+b");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Failed to open %s for modification\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t sz = ftell(fp);
|
||||
|
||||
for (int i = 0; i < patches->nopatchsets; i++) {
|
||||
patchset_t* patchset = patches->patchsets[i];
|
||||
|
||||
if (patchset->name != NULL && strcmp(patchset->name, filename) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < patchset->nopatches; j++) {
|
||||
patch_t patch = patchset->patches[j];
|
||||
if (patch.offset + patch.count > sz) {
|
||||
fprintf(stderr, "E: Patch %s[%d] outside file bounds\n", patchset->name, j);
|
||||
goto done;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
bool matches_from = true;
|
||||
bool matches_to = true;
|
||||
for (int i = 0; i < patch.count; i++) {
|
||||
unsigned char seen;
|
||||
if (!fread(&seen, 1, 1, fp)) {
|
||||
matches_from = false;
|
||||
matches_to = false;
|
||||
break;
|
||||
}
|
||||
if (seen != patch.from[i]) matches_from = false;
|
||||
if (seen != patch.to[i]) matches_to = false;
|
||||
if (!(matches_from || matches_to)) break;
|
||||
}
|
||||
|
||||
printf("%s[%d]: ", patchset->name, j);
|
||||
if (patchset->apply) {
|
||||
if (matches_to) {
|
||||
puts("Already applied");
|
||||
continue;
|
||||
}
|
||||
if (!matches_from) {
|
||||
puts("From value missmatch! Ignoring");
|
||||
continue;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
fwrite(patch.to, 1, patch.count, fp);
|
||||
puts("Patch applied");
|
||||
} else {
|
||||
if (matches_from) {
|
||||
puts("Not applied");
|
||||
continue;
|
||||
}
|
||||
if (!matches_to) {
|
||||
puts("We didn't perform this patch. Leaving patched");
|
||||
continue;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
fwrite(patch.from, 1, patch.count, fp);
|
||||
puts("Patch removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <patch file> <exe>\n", argc > 0 ? argv[0] : "micepatch.exe");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char error[json_error_max];
|
||||
patches_t all_patches;
|
||||
if (!load_patches(&all_patches, argv[1], error)) {
|
||||
fprintf(stderr, "%s\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
puts("");
|
||||
puts("Loaded patches:");
|
||||
puts("---------------");
|
||||
print_patches(&all_patches, argv[2]);
|
||||
apply_patches(&all_patches, argv[2]);
|
||||
free_patches(&all_patches);
|
||||
return 0;
|
||||
}
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "string.h"
|
||||
|
||||
void print_patches(patches_t* patches, char* filename) {
|
||||
for (size_t i = 0; i < patches->nopatchsets; i++) {
|
||||
patchset_t* patchset = patches->patchsets[i];
|
||||
|
||||
bool skip = patchset->name != NULL && strcmp(patchset->name, filename) != 0;
|
||||
|
||||
printf("Patch: %s (%s)\n", patchset->name, skip ? "skipped" : patchset->apply ? "applied" : "unapplied");
|
||||
printf("- %s\n", patchset->description);
|
||||
if (!skip) {
|
||||
for (size_t j = 0; j < patchset->nopatches; j++) {
|
||||
printf(":: %d bytes at %08x\n", patchset->patches[j].count, patchset->patches[j].offset);
|
||||
}
|
||||
}
|
||||
puts("======================");
|
||||
}
|
||||
}
|
||||
|
||||
void apply_patches(patches_t* patches, char* filename) {
|
||||
FILE* fp;
|
||||
fopen_s(&fp, filename, "r+b");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Failed to open %s for modification\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t sz = ftell(fp);
|
||||
|
||||
for (size_t i = 0; i < patches->nopatchsets; i++) {
|
||||
patchset_t* patchset = patches->patchsets[i];
|
||||
|
||||
if (patchset->name != NULL && strcmp(patchset->name, filename) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < patchset->nopatches; j++) {
|
||||
patch_t patch = patchset->patches[j];
|
||||
if (patch.offset + patch.count > sz) {
|
||||
fprintf(stderr, "E: Patch %s[%d] outside file bounds\n", patchset->name, j);
|
||||
goto done;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
bool matches_from = true;
|
||||
bool matches_to = true;
|
||||
for (size_t k = 0; k < patch.count; k++) {
|
||||
unsigned char seen;
|
||||
if (!fread(&seen, 1, 1, fp)) {
|
||||
matches_from = false;
|
||||
matches_to = false;
|
||||
break;
|
||||
}
|
||||
if (seen != patch.from[k]) matches_from = false;
|
||||
if (seen != patch.to[k]) matches_to = false;
|
||||
if (!(matches_from || matches_to)) break;
|
||||
}
|
||||
|
||||
printf("%s[%d]: ", patchset->name, j);
|
||||
if (patchset->apply) {
|
||||
if (matches_to) {
|
||||
puts("Already applied");
|
||||
continue;
|
||||
}
|
||||
if (!matches_from) {
|
||||
puts("From value missmatch! Ignoring");
|
||||
continue;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
fwrite(patch.to, 1, patch.count, fp);
|
||||
puts("Patch applied");
|
||||
} else {
|
||||
if (matches_from) {
|
||||
puts("Not applied");
|
||||
continue;
|
||||
}
|
||||
if (!matches_to) {
|
||||
puts("We didn't perform this patch. Leaving patched");
|
||||
continue;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
fwrite(patch.from, 1, patch.count, fp);
|
||||
puts("Patch removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <patch file> <exe>\n", argc > 0 ? argv[0] : "micepatch.exe");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char error[json_error_max];
|
||||
patches_t all_patches;
|
||||
if (!load_patches(&all_patches, argv[1], error)) {
|
||||
fprintf(stderr, "%s\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
puts("");
|
||||
puts("Loaded patches:");
|
||||
puts("---------------");
|
||||
print_patches(&all_patches, argv[2]);
|
||||
apply_patches(&all_patches, argv[2]);
|
||||
free_patches(&all_patches);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
#include "stdio.h"
|
||||
|
||||
int main() {
|
||||
puts("Hello world");
|
||||
return 0;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
executable(
|
||||
'micetest',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'main.c',
|
||||
],
|
||||
)
|
29
src/micetools/util/meson.build
Normal file
29
src/micetools/util/meson.build
Normal file
@ -0,0 +1,29 @@
|
||||
executable(
|
||||
'micedump',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'micedump.c',
|
||||
],
|
||||
link_with: [
|
||||
amlib
|
||||
],
|
||||
)
|
||||
|
||||
executable(
|
||||
'micetinker',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'micetinker.c',
|
||||
],
|
||||
link_with: [
|
||||
amlib
|
||||
],
|
||||
)
|
||||
|
||||
executable(
|
||||
'micemonitor',
|
||||
win_subsystem: subsystem,
|
||||
sources: [
|
||||
'micemonitor.c',
|
||||
],
|
||||
)
|
271
src/micetools/util/micedump.c
Normal file
271
src/micetools/util/micedump.c
Normal file
@ -0,0 +1,271 @@
|
||||
#include <Windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#pragma comment(lib, "Setupapi.lib")
|
||||
|
||||
#include "../lib/am/amEeprom.h"
|
||||
|
||||
#define OpenDriver(x) \
|
||||
CreateFileA("\\\\.\\" x, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)
|
||||
|
||||
#define RULE "-----------------------------------------"
|
||||
#define SECTION_HEAD(x) \
|
||||
puts(""); \
|
||||
puts(RULE); \
|
||||
puts(x); \
|
||||
puts(RULE); \
|
||||
puts("");
|
||||
|
||||
typedef struct {
|
||||
uint64_t physAddr;
|
||||
DWORD dType;
|
||||
DWORD size;
|
||||
} columba_request_t;
|
||||
|
||||
void scan_for_dmi(HANDLE columba, DWORD *stable_addr) {
|
||||
DWORD bytesOut;
|
||||
// short *stable_len;
|
||||
columba_request_t request;
|
||||
unsigned char readBuf[0x8010];
|
||||
|
||||
uint64_t search_addr = 0xf0000;
|
||||
while (1) {
|
||||
request.physAddr = search_addr;
|
||||
request.dType = 1;
|
||||
request.size = sizeof readBuf;
|
||||
|
||||
BOOL succ = DeviceIoControl(columba, (DWORD)IOCTL_COLUMBA_READ, &request,
|
||||
sizeof request, &readBuf, sizeof readBuf, &bytesOut, NULL);
|
||||
if (succ && bytesOut == sizeof readBuf) {
|
||||
for (unsigned int offset = 0; offset < 0x8008; offset++) {
|
||||
if (readBuf[offset] == '_' && readBuf[offset + 1] == 'D' &&
|
||||
readBuf[offset + 2] == 'M' && readBuf[offset + 3] == 'I' &&
|
||||
readBuf[offset + 4] == '_') {
|
||||
*stable_addr = *(DWORD *)&readBuf[offset + 8];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
search_addr += 0x7ff0;
|
||||
if (search_addr > 0xfffdf) return;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL dump_columba() {
|
||||
SECTION_HEAD("columba");
|
||||
|
||||
HANDLE columba = OpenDriver("columba");
|
||||
if (columba == INVALID_HANDLE_VALUE) return FALSE;
|
||||
|
||||
DWORD stable_addr = 0;
|
||||
scan_for_dmi(columba, &stable_addr);
|
||||
if (stable_addr == 0) {
|
||||
CloseHandle(columba);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
columba_request_t request;
|
||||
unsigned char readBuf[0x10000];
|
||||
|
||||
printf("Found DMI at: %d\n", stable_addr);
|
||||
|
||||
request.physAddr = stable_addr;
|
||||
request.dType = 1;
|
||||
if (stable_addr + 0x10000 < 0x100001) {
|
||||
request.size = 0x10000;
|
||||
} else {
|
||||
request.size = 0x100000 - stable_addr;
|
||||
}
|
||||
DWORD bytesReturned;
|
||||
|
||||
BOOL s = DeviceIoControl(columba, (DWORD)IOCTL_COLUMBA_READ, &request, sizeof request,
|
||||
readBuf, sizeof readBuf, &bytesReturned, NULL);
|
||||
if (!s || bytesReturned != sizeof readBuf) {
|
||||
CloseHandle(columba);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
puts("DMI read sucessful.");
|
||||
FILE *dmi;
|
||||
fopen_s(&dmi, "dmi.bin", "wb");
|
||||
fwrite(readBuf, 1, sizeof readBuf, dmi);
|
||||
fclose(dmi);
|
||||
puts(" -> Written to dmi.bin");
|
||||
|
||||
CloseHandle(columba);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL dump_eeprom() {
|
||||
SECTION_HEAD("mxSMBus");
|
||||
|
||||
HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0);
|
||||
if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE;
|
||||
|
||||
DWORD _dummy;
|
||||
DWORD version;
|
||||
DeviceIoControl(mxsmbus, (DWORD)IOCTL_MXSMBUS_GET_VERSION, NULL, 0, &version, sizeof version,
|
||||
&_dummy, NULL);
|
||||
printf("mxSMBus version: %08x\n", version);
|
||||
|
||||
BYTE data[0x20];
|
||||
for (WORD reg = 0; reg < 256; reg++) {
|
||||
if (!amEepromReadBlock(mxsmbus, reg & 0xFF, 0x20, data)) continue;
|
||||
printf("%02x: ", reg);
|
||||
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
|
||||
puts("");
|
||||
}
|
||||
|
||||
CloseHandle(mxsmbus);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
unsigned char sram_buf[1024 * 2048];
|
||||
BOOL dump_sram() {
|
||||
SECTION_HEAD("mxSRAM");
|
||||
|
||||
HANDLE mxsram = OpenDriver("mxsram");
|
||||
if (mxsram == INVALID_HANDLE_VALUE) return FALSE;
|
||||
|
||||
DWORD _dummy;
|
||||
BOOL s;
|
||||
|
||||
DWORD version;
|
||||
s = DeviceIoControl(mxsram, (DWORD)IOCTL_MXSRAM_PING, NULL, 0, &version, sizeof version,
|
||||
&_dummy, NULL);
|
||||
if (!s) {
|
||||
CloseHandle(mxsram);
|
||||
return FALSE;
|
||||
}
|
||||
printf("mxSRAM version: %04x\n", version);
|
||||
|
||||
DISK_GEOMETRY geom;
|
||||
s = DeviceIoControl(mxsram, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof geom, &_dummy,
|
||||
NULL);
|
||||
if (!s) {
|
||||
CloseHandle(mxsram);
|
||||
return FALSE;
|
||||
}
|
||||
puts("mxSRAM geometry:");
|
||||
printf(":: Cylinders: %lld\n", geom.Cylinders.QuadPart);
|
||||
printf(":: MediaType: %d\n", geom.MediaType);
|
||||
printf(":: TracksPerCylinder: %d\n", geom.TracksPerCylinder);
|
||||
printf(":: SectorsPerTrack: %d\n", geom.SectorsPerTrack);
|
||||
printf(":: BytesPerSector: %d\n", geom.BytesPerSector);
|
||||
|
||||
DWORD ssize;
|
||||
s = DeviceIoControl(mxsram, (DWORD)IOCTL_MXSRAM_GET_SECTOR_SIZE, NULL, 0, &ssize, sizeof ssize,
|
||||
&_dummy, NULL);
|
||||
if (!s) {
|
||||
CloseHandle(mxsram);
|
||||
return FALSE;
|
||||
}
|
||||
printf(":: Sector Size: %d\n", ssize);
|
||||
|
||||
DWORD read;
|
||||
if (!ReadFile(mxsram, sram_buf, sizeof sram_buf, &read, NULL)) {
|
||||
CloseHandle(mxsram);
|
||||
return FALSE;
|
||||
}
|
||||
printf("Read %d bytes\n", read);
|
||||
if (read != sizeof sram_buf) puts("W: incomplete");
|
||||
|
||||
FILE *sram;
|
||||
fopen_s(&sram, "sram.bin", "wb");
|
||||
fwrite(sram_buf, 1, sizeof sram_buf, sram);
|
||||
fclose(sram);
|
||||
puts(" -> Written to sram.bin");
|
||||
CloseHandle(mxsram);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BYTE superio_read(HANDLE mxsuperio, BYTE chip, BYTE device, BYTE index) {
|
||||
DWORD _dummy;
|
||||
BYTE payload[4] = { chip, device, index, 0 };
|
||||
DeviceIoControl(mxsuperio, (DWORD)IOCTL_MXSUPERIO_READ, payload, sizeof payload, payload,
|
||||
sizeof payload, &_dummy, NULL);
|
||||
return payload[3];
|
||||
}
|
||||
|
||||
#define SUPERIO_LD_FDC 0
|
||||
#define SUPERIO_LD_PARALLEL 1
|
||||
#define SUPERIO_LD_UART_A 2
|
||||
#define SUPERIO_LD_UART_B 3
|
||||
#define SUPERIO_LD_KEYBOARD 5
|
||||
#define SUPERIO_LD_UART_C 6
|
||||
#define SUPERIO_LD_GPIO34 7
|
||||
#define SUPERIO_LD_WDTO_PLED_GPIO56 8
|
||||
#define SUPERIO_LD_GPIO12_SUSLED 9
|
||||
#define SUPERIO_LD_ACPI 10
|
||||
#define SUPERIO_LD_HWMON 11
|
||||
#define SUPERIO_LD_PECI_SST 12
|
||||
#define SUPERIO_LD_UART_D 13
|
||||
#define SUPERIO_LD_UART_E 14
|
||||
#define SUPERIO_LD_UART_F 15
|
||||
|
||||
BOOL dump_superio() {
|
||||
SECTION_HEAD("mxSuperIO");
|
||||
|
||||
HANDLE mxsuperio = OpenDriver("mxsuperio");
|
||||
if (mxsuperio == INVALID_HANDLE_VALUE) return FALSE;
|
||||
BOOL s;
|
||||
DWORD _dummy;
|
||||
|
||||
DWORD version;
|
||||
s = DeviceIoControl(mxsuperio, (DWORD)IOCTL_MXSUPERIO_PING, NULL, 0, &version, sizeof version,
|
||||
&_dummy, NULL);
|
||||
if (!s) {
|
||||
CloseHandle(mxsuperio);
|
||||
return FALSE;
|
||||
}
|
||||
printf("mxSuperIO version: %08x\n", version);
|
||||
|
||||
BYTE ver_msb;
|
||||
ver_msb = superio_read(mxsuperio, 0, SUPERIO_LD_FDC, 0x20);
|
||||
if (ver_msb != 0xff) {
|
||||
puts(":: Chip 0 present");
|
||||
printf(" -> Version: %02x%02x\n", ver_msb,
|
||||
superio_read(mxsuperio, 0, SUPERIO_LD_FDC, 0x21));
|
||||
} else
|
||||
puts(":: Chip 0 unpopulated");
|
||||
ver_msb = superio_read(mxsuperio, 1, SUPERIO_LD_FDC, 0x20);
|
||||
if (ver_msb != 0xff) {
|
||||
puts(":: Chip 1 present");
|
||||
printf(" -> Version: %02x%02x\n", ver_msb,
|
||||
superio_read(mxsuperio, 1, SUPERIO_LD_FDC, 0x21));
|
||||
} else
|
||||
puts(":: Chip 1 unpopulated");
|
||||
|
||||
puts(":: Super lazy dump of chip 1, bank 0:");
|
||||
for (uint8_t reg = 0; reg < 0xff; reg++) {
|
||||
unsigned char packet[3] = { 1, reg, 0 };
|
||||
DeviceIoControl(mxsuperio, (DWORD)IOCTL_MXSUPERIO_HWMONITOR_LPC_READ, &packet,
|
||||
sizeof packet, &packet, sizeof packet, &_dummy, NULL);
|
||||
printf(" -> %02x: %02x\n", reg, packet[2]);
|
||||
}
|
||||
|
||||
CloseHandle(mxsuperio);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// if (!dump_columba()) {
|
||||
// printf("Failed to dump DMI: %03x\n", GetLastError());
|
||||
// }
|
||||
if (!dump_eeprom()) {
|
||||
printf("Failed to dump EEPROM: %03x\n", GetLastError());
|
||||
}
|
||||
// if (!dump_sram()) {
|
||||
// printf("Failed to dump SRAM: %03x\n", GetLastError());
|
||||
// }
|
||||
// if (!dump_superio()) {
|
||||
// printf("Failed to dump SuperIO: %03x\n", GetLastError());
|
||||
// }
|
||||
return 0;
|
||||
}
|
14
src/micetools/util/micemonitor.c
Normal file
14
src/micetools/util/micemonitor.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define P2A_PATH "C:\\ProgramData\\boost_interprocess\\ALLNetComP2A"
|
||||
#define A2P_PATH "C:\\ProgramData\\boost_interprocess\\ALLNetComA2P"
|
||||
|
||||
int main(int argc, char* argv) {
|
||||
FILE* f;
|
||||
fopen_s(&f, "./test.txt", "w");
|
||||
fprintf(f, "count: %d", argc);
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
57
src/micetools/util/micetinker.c
Normal file
57
src/micetools/util/micetinker.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <Windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#pragma comment(lib, "Setupapi.lib")
|
||||
|
||||
#include "../lib/am/amEeprom.h"
|
||||
|
||||
BOOL change_region(BYTE region) {
|
||||
HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0);
|
||||
if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE;
|
||||
|
||||
BYTE data[0x20];
|
||||
if (!amEepromReadBlock(mxsmbus, 0, sizeof data, data)) {
|
||||
printf("Failed to read block 0");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
puts("Original content:");
|
||||
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
|
||||
puts("");
|
||||
|
||||
data[12] = region;
|
||||
amEepromRepairChecksum(data);
|
||||
|
||||
amEepromWriteBlock(mxsmbus, 0, sizeof data, data);
|
||||
amEepromReadBlock(mxsmbus, 0, sizeof data, data);
|
||||
|
||||
puts("Tinkered content:");
|
||||
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
|
||||
puts("");
|
||||
|
||||
CloseHandle(mxsmbus);
|
||||
return TRUE;
|
||||
fail:
|
||||
CloseHandle(mxsmbus);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <region>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
BYTE region = argv[1][0] - '0';
|
||||
printf("Changing to region: %d\n", region);
|
||||
|
||||
if (!change_region(region)) {
|
||||
printf("Failed to change region: %03x", GetLastError());
|
||||
} else {
|
||||
printf("Region changed!");
|
||||
}
|
||||
return 0;
|
||||
}
|
9
src/patches/mxgfetcher.patch.json
Normal file
9
src/patches/mxgfetcher.patch.json
Normal file
@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "LOG_EN_AMSRAM",
|
||||
"at": "00465e54",
|
||||
"from": "00000000",
|
||||
"to": "01000000",
|
||||
"count": 4
|
||||
}
|
||||
]
|
@ -1,51 +1,58 @@
|
||||
[
|
||||
{
|
||||
"name": "maimai Finale logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "maimai_dump_.exe",
|
||||
"apply": true,
|
||||
"patches_file": "maimai_dump_.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxnetwork logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "mxnetwork.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxnetwork.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "maimai 1.00 logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "Game.exe",
|
||||
"apply": true,
|
||||
"patches_file": "Game.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "ALLNetProc logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "ALLNetProc.exe",
|
||||
"apply": true,
|
||||
"patches_file": "ALLNetProc.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "ALLNetProc logs",
|
||||
"description": "Enable logging facilities (alt filename)",
|
||||
"binary_name": "ALLNetProc_win.exe",
|
||||
"apply": true,
|
||||
"patches_file": "ALLNetProc.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxsegaboot logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "mxsegaboot.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxsegaboot.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxsegaboot logs",
|
||||
"description": "Enable logging facilities (alt filename)",
|
||||
"binary_name": "ORIG_mxsegaboot.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxsegaboot.patch.json"
|
||||
}
|
||||
[
|
||||
{
|
||||
"name": "maimai Finale logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "maimai_dump_.exe",
|
||||
"apply": true,
|
||||
"patches_file": "maimai_dump_.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxnetwork logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "mxnetwork.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxnetwork.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "maimai 1.00 logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "Game.exe",
|
||||
"apply": true,
|
||||
"patches_file": "Game.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "ALLNetProc logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "ALLNetProc.exe",
|
||||
"apply": true,
|
||||
"patches_file": "ALLNetProc.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "ALLNetProc logs",
|
||||
"description": "Enable logging facilities (alt filename)",
|
||||
"binary_name": "ALLNetProc_win.exe",
|
||||
"apply": true,
|
||||
"patches_file": "ALLNetProc.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxsegaboot logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "mxsegaboot.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxsegaboot.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxsegaboot logs",
|
||||
"description": "Enable logging facilities (alt filename)",
|
||||
"binary_name": "ORIG_mxsegaboot.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxsegaboot.patch.json"
|
||||
},
|
||||
{
|
||||
"name": "mxgfetcher logs",
|
||||
"description": "Enable logging facilities",
|
||||
"binary_name": "mxgfetcher.exe",
|
||||
"apply": true,
|
||||
"patches_file": "mxgfetcher.patch.json"
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user